diff --git a/client/inc/nb65_constants.i b/client/inc/nb65_constants.i index ce4f622..0de4378 100644 --- a/client/inc/nb65_constants.i +++ b/client/inc/nb65_constants.i @@ -33,7 +33,6 @@ NB65_SEND_UDP_PACKET EQU $12 ;inputs: AX points to a UDP packet parame NB65_UDP_REMOVE_LISTENER EQU $13 ;inputs: AX contains UDP port number that listener will be removed from NB65_TFTP_SET_SERVER EQU $20 ;inputs: AX points to a TFTP server parameter structure, outputs: none -NB65_TFTP_DIRECTORY_LISTING EQU $21 ;inputs: AX points to a TFTP transfer parameter structure, outputs: none NB65_TFTP_DOWNLOAD EQU $22 ;inputs: AX points to a TFTP transfer parameter structure, outputs: TFTP param structure updated with ;NB65_TFTP_POINTER updated to reflect actual load address (if load address $0000 originally passed in) NB65_TFTP_CALLBACK_DOWNLOAD EQU $23 ;inputs: AX points to a TFTP transfer parameter structure, outputs: none diff --git a/client/ip65/function_dispatcher.s b/client/ip65/function_dispatcher.s index ea273cb..5fe7512 100644 --- a/client/ip65/function_dispatcher.s +++ b/client/ip65/function_dispatcher.s @@ -17,7 +17,6 @@ .import tftp_load_address .importzp tftp_filename .import tftp_ip -.import tftp_directory_listing .import ip65_error .import tftp_clear_callbacks .import tftp_download @@ -310,11 +309,11 @@ ip_configured: rts : - cpy #NB65_TFTP_DIRECTORY_LISTING + cpy #NB65_TFTP_DOWNLOAD bne :+ phax jsr set_tftp_params - jsr tftp_directory_listing + jsr tftp_download @after_tftp_call: ;write the current load address back to the param buffer (so if $0000 was passed in, the caller can find out the actual value used) plax @@ -339,13 +338,6 @@ ip_configured: rts : - cpy #NB65_TFTP_DOWNLOAD - bne :+ - phax - jsr set_tftp_params - jsr tftp_download - jmp @after_tftp_call -: cpy #NB65_TFTP_CALLBACK_DOWNLOAD diff --git a/client/ip65/tftp.s b/client/ip65/tftp.s index 75896f9..2d1c05b 100644 --- a/client/ip65/tftp.s +++ b/client/ip65/tftp.s @@ -1,5 +1,5 @@ ;minimal tftp implementation (client only) -;supports file download and upload and custom directory listing (using non-standard tftp opcode of 0x65) +;supports file upload and download TFTP_MAX_RESENDS=10 @@ -16,7 +16,6 @@ .export tftp_ip .export tftp_download .export tftp_upload - .export tftp_directory_listing .export tftp_data_block_length .export tftp_set_callback_vector .export tftp_data_block_length @@ -133,29 +132,6 @@ tftp_upload: ldax #$0200 ;opcode 02 = WRQ jmp set_tftp_opcode -; query a tftp server for a directory listing (uses a non-standard tftp opcode, -; currently only supported by tftp server built in to 'netboot65' server) -; inputs: -; tftp_ip: ip address of host to download from (set to 255.255.255.255 for broadcast) -; tftp_filename: pointer to null terminated filemask (e.g. "*.prg",0) -; tftp_load_address: memory location that dir will be stored in (NB - this field is -; ignored if a callback vector has been set with tftp_set_callback_vector) -; outputs: carry flag is set if there was an error, clear otherwise -; if a callback vector has been set with tftp_set_callback_vector -; then the specified routine will be called once for each 512 byte packet -; sent from the tftp server (each time AX will point at data block just arrived, -; and tftp_data_block_length will contain number of bytes in that data block) -; otherwise, the buffer at tftp_load_address will be filled -; with null-terminated strings containing the names of all files on the -; server that matched the specified file mask, and an additional null -; byte will follow the null byte terminating the last file name. -; NB - there is no limit to the amount of memory this function will consume, -; so depending on where tftp_load_address is set, there is potential to -; overwrite other data or code -tftp_directory_listing: - ldax #$6500 ;opcode 65 = netboot65 DIR (non-standard opcode) - jmp set_tftp_opcode - ;download a file from a tftp server ; inputs: ; tftp_ip: ip address of host to download from (set to 255.255.255.255 for broadcast) @@ -187,9 +163,9 @@ set_tftp_opcode: stax tftp_current_memloc ldax #tftp_in stax udp_callback - lda #$69 + ldx #$69 inc tftp_client_port_low_byte ;each transfer uses a different client port - ldx tftp_client_port_low_byte ;so we don't get confused by late replies to a previous call + lda tftp_client_port_low_byte ;so we don't get confused by late replies to a previous call jsr udp_add_listener bcc :+ ;bail if we couldn't listen on the port we want @@ -218,8 +194,8 @@ set_tftp_opcode: bne @not_error @exit_with_error: - lda #$69 - ldx tftp_client_port_low_byte + ldx #$69 + lda tftp_client_port_low_byte jsr udp_remove_listener sec rts @@ -229,8 +205,8 @@ set_tftp_opcode: cmp #tftp_complete bne @not_complete jsr send_ack ;send the ack for the last block - lda #$69 - ldx tftp_client_port_low_byte + ldx #$69 + lda tftp_client_port_low_byte jsr udp_remove_listener rts @@ -293,8 +269,8 @@ send_request_packet: ldx #0 stax udp_send_len - lda #$69 - ldx tftp_client_port_low_byte + ldx #$69 + lda tftp_client_port_low_byte stax udp_send_src_port ldx #3 ; set destination address @@ -328,8 +304,8 @@ send_tftp_packet: ;TFTP block should be created in tftp_outp, we just add the UD lda tftp_current_block_number+1 stax tftp_outp+2 - lda #$69 - ldx tftp_client_port_low_byte + ldx #$69 + lda tftp_client_port_low_byte stax udp_send_src_port lda tftp_actual_server_ip diff --git a/client/nb65/nb65_c64.s b/client/nb65/nb65_c64.s index 57e7200..acf0f09 100644 --- a/client/nb65/nb65_c64.s +++ b/client/nb65/nb65_c64.s @@ -391,7 +391,7 @@ cmp #KEYCODE_F7 jsr print_cr ldax #nb65_param_buffer - nb65call #NB65_TFTP_DIRECTORY_LISTING + nb65call #NB65_TFTP_DOWNLOAD bcs @dir_failed @@ -569,7 +569,7 @@ new: .byte"NEW ",0 tftp_dir_filemask: - .asciiz "*.PRG" + .asciiz "$*.prg" tftp_file: .asciiz "BOOTC64.PRG" diff --git a/client/nb65/utherboot.s b/client/nb65/utherboot.s index e4e3a07..8e50313 100644 --- a/client/nb65/utherboot.s +++ b/client/nb65/utherboot.s @@ -21,7 +21,6 @@ .import tftp_load_address .import tftp_ip .import tftp_download - .import tftp_directory_listing .import copymem .importzp copy_src @@ -175,7 +174,7 @@ init: jsr print jsr print_cr - jsr tftp_directory_listing + jsr tftp_download bcs @dir_failed ldax #$0000 ;load address will be first 2 bytes of file we download (LO/HI order) @@ -286,7 +285,7 @@ tftp_file: .asciiz "BOOTA2.PG2" tftp_dir_filemask: - .asciiz "*.PG2" + .asciiz "$*.pg2" tftp_download_fail_msg: .asciiz "DOWNLOAD FAILED" diff --git a/server/bin/tftp_only_server.rb b/server/bin/tftp_only_server.rb index c3117ce..6243050 100644 --- a/server/bin/tftp_only_server.rb +++ b/server/bin/tftp_only_server.rb @@ -18,8 +18,8 @@ require 'tftp_server' bootfile_dir=File.expand_path(File.dirname(__FILE__)+'/../boot') tftp_server_69=Netboot65TFTPServer.new(bootfile_dir,69) tftp_server_69.start -tftp_server_6502=Netboot65TFTPServer.new(bootfile_dir,6502) -tftp_server_6502.start +#tftp_server_6502=Netboot65TFTPServer.new(bootfile_dir,6502) +#tftp_server_6502.start begin loop do @@ -28,5 +28,6 @@ begin rescue Interrupt log_msg "got interrupt signal - shutting down" end -tftp_server_6502.shutdown +tftp_server.shutdown +#tftp_server_6502.shutdown log_msg "shut down complete." diff --git a/server/lib/tftp_server.rb b/server/lib/tftp_server.rb index dd9efa1..7532b52 100644 --- a/server/lib/tftp_server.rb +++ b/server/lib/tftp_server.rb @@ -1,7 +1,8 @@ # # minimal TFTP server implementation for use with netboot65 # -# supports RRQ, WRQ and a custom DIR request (opcode 0x65 - returns null terminated list of filenames that match specified filemask) +# supports RRQ, WRQ +# a RRQ for a filename starting with $ is treated as a directory request # Jonno Downes (jonno@jamtronix.com) - January, 2009 # # TFTP spec : http://www.ietf.org/rfc/rfc1350.txt @@ -17,7 +18,6 @@ class Netboot65TFTPServer 3=>'DATA', 4=>'ACK', 5=>'ERROR', - 0x65=>'DIR', } TFTP_ERRORCODES={ @@ -167,7 +167,16 @@ class Netboot65TFTPServer log_msg "RRQ for #{filename} (#{mode})" if filename=~/^\./ || filename=~/\.\./ then #looks like something dodgy - either a dotfile or a directory traversal attempt send_error(client_ip,client_port,1,"'#{filename}' invalid filename") - else + elsif filename=~/^\$(.*)/ then #it's a directory request + filemask=$1 + log_msg "DIR for #{filemask}" + data_to_send="" + Dir.chdir(bootfile_dir) do + Dir.glob(filemask).each {|filename| data_to_send<<"#{filename}\000"} + end + data_to_send<<0.chr + Thread.new {send_data(client_ip,client_port,"DIR of #{filemask}",data_to_send)} + else full_filename="#{bootfile_dir}/#{filename}" if File.file?(full_filename) then data_to_send=File.open(full_filename,"rb").read