\ ========== Copyright Header Begin ==========================================
\ Hypervisor Software File: tftp.fth
\ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
\ - Do no alter or remove copyright notices
\ - Redistribution and use of this software in source and binary forms, with
\ or without modification, are permitted provided that the following
\ - Redistribution of source code must retain the above copyright notice,
\ this list of conditions and the following disclaimer.
\ - Redistribution in binary form must reproduce the above copyright notice,
\ this list of conditions and the following disclaimer in the
\ documentation and/or other materials provided with the distribution.
\ Neither the name of Sun Microsystems, Inc. or the names of contributors
\ may be used to endorse or promote products derived from this software
\ without specific prior written permission.
\ This software is provided "AS IS," without a warranty of any kind.
\ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
\ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
\ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
\ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
\ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
\ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
\ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
\ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
\ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
\ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
\ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
\ You acknowledge that this software is not designed, licensed or
\ intended for use in the design, construction, operation or maintenance of
\ ========== Copyright Header End ============================================
id: @(#)tftp.fth 2.24 02/08/22
purpose: Trivial File Transfer Protocol (TFTP) implementation
copyright: Copyright 1990-2002 Sun Microsystems, Inc. All Rights Reserved
copyright: Use is subject to license terms.
\ Trivial File Transfer Protocol
d# 128 instance buffer: tftp-file-buf
' tftp-file-buf to tftp-file
: opcode ( -- ) active-struct@ >opcode ;
: block# ( -- ) active-struct@ >block# ;
: filename ( -- ) active-struct@ >filename ;
: errorcode ( -- ) active-struct@ >errorcode ;
: errmsg ( -- ) active-struct@ >errmsg ;
: data ( -- ) active-struct@ >data ;
instance variable this-block
instance variable #retries
instance variable #packet
false instance value first-try?
-1 instance value tftp-retries
: too-many-tftp-retries? ( -- flag ) \ flag true if too many retries
#retries @ tftp-retries u>=
use-server? use-dhcp @ or if
." TFTP Error: " errmsg dup cstrlen type
UP_TFTP did ! \ Unlock from server
: $cstrput ( from-adr,len to-adr -- end-adr )
3dup swap move ( from-adr,len to-adr )
: setup-request ( file-name-str rrq-pkt/wrq-pkt -- )
packet-to-send active-struct !
UP_TFTP did ! ( file-name rrq-pkt/wrq-pkt )
opcode be-w! ( file-name-str )
filename $cstrput ( mode-adr )
packet-to-send - #packet !
: setup-read-request ( file-name-string -- )
: setup-write-request ( file-name-string -- )
: setup-ack-packet ( -- )
packet-to-send active-struct !
this-block @ block# be-w!
: send-packet ( tftp-adr tftp-len -- #sent )
( tftp-adr tftp-len ) prepare-udp-packet ( len )
." TFTP send failed. Check Ethernet cable and transceiver" cr
0 instance value error-packet \ Buffer address
: send-error-packet ( -- )
/tftp-packet alloc-mem to error-packet
udp-source-port be-w@ did ! \ set the udp-source-port to the port indicated
\ in the received error packet.
error-packet active-struct !
5 ( Unknown transfer ID ) errorcode be-w!
" Unknown source address" errmsg $cstrput ( end-address )
error-packet tuck - ( packet-adr len )
r> did ! \ restore the previous did
error-packet /tftp-packet free-mem
: unlock-dest-ip-en-addr ( -- )
use-server? use-router? use-dhcp @ or or if exit then
broadcast-ip-addr his-ip-addr 4 cmove
broadcast-en-addr his-en-addr 6 cmove
: lock-dest-ip-en-addr ( -- )
dup /ip-header - active-struct !
ip-source-addr his-ip-addr 4 cmove
/ether-header negate active-struct +!
en-source-addr his-en-addr 6 cmove
his-ip-addr server-ip-addr 4 cmove
\ Check source port against destination id.
\ If it mismatches, error unless did is currently 69
: bad-src-port? ( -- error ) \ assumes active-struct is udp
udp-source-port be-w@ did @ <> if
udp-source-port be-w@ did ! \ Lock onto his port
his-ip-addr broadcast-ip-addr? if
lock-dest-ip-en-addr \ Lock onto dest ip & ether addresses
\ Check block number. Assumes active-struct is tftp.
: bad-block#? ( -- error? ) block# be-w@ this-block @ <> ;
: send-current-packet ( -- #sent ) packet-to-send #packet @ send-packet ;
: receive-tftp-packet ( -- [ tftp-pkt-adr tftp-pkt-len ] flag )
receive-udp-packet 0= if false exit then ( udp-pkt udp-len )
udp-dest-port be-w@ sid @ =
bad-src-port? if send-error-packet false exit then
active-struct @ /udp-header + ( tftp-pkt-adr )
udp-length be-w@ /udp-header - ( tftp-pkt-adr tftp-len )
: receive-data-packet ( -- [ data-adr data-len ] flag )
receive-tftp-packet 0= if false exit then ( tftp-adr tftp-len )
over active-struct ! ( tftp-adr tftp-len )
opcode be-w@ data-pkt <> bad-block#? or
opcode be-w@ err-pkt = if .merror then
repeat ( tftp-adr tftp-len )
\ Relock the destination port number
\ Give the server to come back up. Delay
\ re-broadcasting to avoid jaming up the net.
#retries @ if 5000 ms then
: get-data-packet ( adr -- adr' more? )
#retries @ d# 10 /mod drop 0= if
." Retrying ... Check TFTP server and network setup" cr
too-many-tftp-retries? if
." TFTP retry count exceeded" cr false exit
\ Copy data from packet to our buffer at addr
r> d# 512 = ( adr' more? )
: need-router? ( -- flag )
server-ip-addr be-l@ on-my-net? 0=
/tftp-packet alloc-mem to packet-to-send
/udp-pseudo-hdr alloc-mem to udp-pseudo-hdr
get-msecs h# 0ffff and sid ! \ "random" number
packet-to-send /tftp-packet free-mem
udp-pseudo-hdr /udp-pseudo-hdr free-mem
: tftpread ( adr file-name -- size )
tftp-init ( adr file-name )
reserve-buffer ( adr file-name )
setup-read-request ( adr )
get-data-packet ( adr adr' more? )
show-progress setup-ack-packet
\ Send the final acknowledge. Don't send if receive error.
too-many-tftp-retries? 0= if
send-current-packet drop \ ignore errors
tftp-close too-many-tftp-retries? if ." tftp failed" abort then
\ *** New routines for tftpwrite ***
: receive-ack-packet ( -- [ ack-packet-adr ack-len ] flag )
\ flag is true if good packet. other entries only if flag true
receive-tftp-packet ( [ tftp-packet-adr tftp-len ] flag )
0= if false exit then ( packet-adr len )
opcode be-w@ err-pkt = if .merror 2drop false exit then
opcode be-w@ ack-pkt <> if
." Got a non-ack packet" 2drop false exit
bad-block#? if 2drop false else nip data swap 4 - true then
: get-ack-packet ( -- ack-received? )
receive-ack-packet ( [ ack-packet-adr ack-len ] flag )
\ XXX we need to be able to retry the whole transaction at a higher
\ level, so we should exit more gracefully than we do here.
too-many-tftp-retries? if ." receive failed" false exit then
: setup-data-packet ( adr sizeleft -- adr' sizeleft' done? )
packet-to-send active-struct !
this-block @ block# be-w! ( adr sizeleft )
2dup d# 512 min ( adr sizeleft adr size<=512 )
d# 512 - \ decrease size remaining
swap d# 512 + swap \ adjust addr for remaining data
: tftpwrite ( adr size file-name -- )
reserve-buffer ( adr size )
setup-write-request ( adr size )
setup-data-packet ( adr' sizeleft' done? )
else true \ error exit from loop