Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / obp / obp / pkg / netinet / tftp.fth
\ ========== 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
\ conditions are met:
\
\ - 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
\ any nuclear facility.
\
\ ========== Copyright Header End ============================================
id: @(#)tftp.fth 1.2 05/03/25
purpose: TFTP support
copyright: Copyright 2005 Sun Microsystems, Inc. All Rights Reserved
copyright: Use is subject to license terms.
\ RFC 906: Bootstrap loading using TFTP
\ RFC 1350: The TFTP Protocol
fload ${BP}/pkg/netinet/tftp-h.fth
headerless
0 instance value tftp-sockid
/timer instance buffer: tftp-timer
/insock instance buffer: tftp-cli-addr
/insock instance buffer: tftp-srv-addr
/insock instance buffer: tftp-from-addr
instance variable tftp-from-len
0 instance value tftp-sndbuf
instance variable tftp-sndbuflen
0 instance value tftp-rcvbuf
instance variable tftp-nextblk#
0 instance value tftp-retries
: tftp-init ( siaddr -- )
tftp-cli-addr my-ip-addr 0 insock-init ( ipaddr )
tftp-srv-addr swap IPPORT_TFTP insock-init ( )
/tftp-packet alloc-mem to tftp-sndbuf ( )
/tftp-packet alloc-mem to tftp-rcvbuf ( )
AF_INET SOCK_DGRAM IPPROTO_UDP socreate to tftp-sockid ( )
tftp-sockid tftp-cli-addr /insock sobind ( )
;
: tftp-close ( -- )
tftp-sndbuf /tftp-packet free-mem
tftp-rcvbuf /tftp-packet free-mem
tftp-sockid soclose
;
\ Send a packet to the TFTP server
: tftp-send-packet ( -- )
tftp-sockid tftp-sndbuf tftp-sndbuflen @ 0 tftp-srv-addr /insock
sosendto 0< if
." TFTP: Could not send to "
tftp-srv-addr .insock tftp-sockid .soerror -1 throw
then
;
\ Send a TFTP read request
: tftp-send-rrq ( mode$ file$ -- )
tftp-sndbuf >r ( mode$ file$ ) ( r: pkt )
TFTP_RRQ r@ >tftp-opcode htonw! ( mode$ file$ )
r@ >tftp-file $cstrput ( mode$ adr )
$cstrput ( adr' )
r> - tftp-sndbuflen ! ( ) ( r: )
1 tftp-nextblk# ! ( )
tftp-send-packet ( )
;
\ Format and send a TFTP ack packet.
: tftp-send-ack ( block# -- )
tftp-sndbuf ( block# pkt )
TFTP_ACK over >tftp-opcode htonw! ( block# pkt )
>tftp-block# htonw! ( )
/tftp-header tftp-sndbuflen ! ( )
tftp-send-packet ( )
;
\ Format a TFTP ERROR packet and send it to the specified endpoint. Used
\ to reject connections once a connection to a TFTP server has been
\ established.
: tftp-send-error ( insock -- )
/tftp-packet alloc-mem swap >r ( pkt ) ( r: insock )
TFTP_ERROR over >tftp-opcode htonw! ( pkt )
5 over >tftp-errcode htonw! ( pkt )
" Unknown transfer ID" ( pkt $ )
2 pick >tftp-data $cstrput ( pkt pktend )
over tuck - ( pkt pkt len )
tftp-sockid -rot 0 r> /insock sosendto drop ( pkt ) ( r: )
/tftp-packet free-mem ( )
;
\ Managing timeouts and retransmissions. Use a simple exponential backoff
\ strategy (with a maximum timeout of 32 seconds) between retries. Abort
\ the file transfer if the maximum number of retries has been exceeded.
: tftp-retransmit-packet ( -- )
tftp-retries tftp-max-retries u> if ( )
." TFTP: Transfer timed out" -1 throw
then ( )
tftp-retries 1+ dup to tftp-retries ( n )
d# 10 mod 0= if ( )
." Timed out waiting for TFTP reply" cr ( )
then ( )
tftp-send-packet ( )
;
: tftp-backoff ( -- )
tftp-timer dup clear-timer 2* d# 32000 min set-timer
;
\ Process incoming TFTP packets addressed to our port. If this is an
\ ERROR packet, we accept the error only if the we know the TFTP
\ server's address and the error is on this connection.
: (tftp-receive-packet) ( -- pkt len )
tftp-sockid tftp-rcvbuf tuck /tftp-packet 0 tftp-from-addr tftp-from-len
sorecvfrom
;
: tftp-receive-packet ( -- pkt len true | false )
(tftp-receive-packet) dup 0= if 2drop false exit then
over >tftp-opcode ntohw@ TFTP_ERROR = if ( pkt len )
tftp-srv-addr >sin-addr dup ip=broadcast? if ( pkt len ipaddr )
3drop false exit ( false )
then ( pkt len ipaddr )
tftp-from-addr >sin-addr ip<> if ( pkt len )
2drop false exit ( false )
then ( pkt len )
drop >tftp-errmsg cscount ( error$ )
." TFTP Error: " type cr -1 throw ( )
then ( pkt len )
true ( pkt len true )
;
\ Processing TFTP DATA packets. If this is the first response, register
\ the server's IP address and port number (TID). Once a connection has
\ been established, other connections are rejected by returning an
\ ERROR packet.
: (tftp-receive-data) ( -- pkt len true | false )
tftp-receive-packet 0= if false exit then ( pkt len )
over >tftp-opcode ntohw@ TFTP_DATA <> if ( pkt len )
2drop false exit ( false )
then ( pkt len )
tftp-srv-addr dup >sin-port ntohw@ IPPORT_TFTP = if ( pkt len srvaddr )
tftp-from-addr insock>addr,port insock-init true ( pkt len true )
else ( pkt len srvaddr )
tftp-from-addr insock= if ( pkt len )
true ( pkt len true )
else ( pkt len )
tftp-from-addr tftp-send-error 2drop false ( false )
then ( pkt len true | false )
then ( pkt len true | false )
;
: tftp-receive-data ( -- pkt len true | false )
(tftp-receive-data) if ( pkt len )
over >tftp-block# ntohw@ dup >r ( pkt len blk ) ( r: blk )
tftp-nextblk# @ = if ( pkt len )
1 tftp-nextblk# +! true ( pkt len true )
else ( pkt len )
2drop false ( false )
then ( pkt len true | false )
r> tftp-send-ack ( pkt len true | false ) ( r: )
else ( )
false ( false )
then ( pkt len true | false )
;
\ Wait for a DATA packet to arrive.
: (tftp-read-data) ( -- data datalen true | false )
begin tftp-timer timer-expired? 0= while ( )
tftp-receive-data if ( pkt len )
/tftp-header encapsulated-data true exit ( data datalen true )
then ( )
repeat false ( false )
;
\ Copy TFTP segment data to memory and check if there's more data to come.
: tftp-read-data ( adr -- adr' more? )
tftp-timer d# 4000 set-timer ( adr )
begin (tftp-read-data) 0= while ( adr )
tftp-retransmit-packet tftp-backoff ( adr )
repeat ( adr data datalen )
>r over r@ move r@ ca+ r> TFTP_SEGSIZE = ( adr' more? )
;
: tftp-read ( adr filename$ -- size )
" octet" 2swap tftp-send-rrq ( adr )
dup begin tftp-read-data while ( adr adr' )
show-progress ( adr adr' )
repeat swap - ( size )
;
: tftp-load ( adr filename$ siaddr -- size )
tftp-init ( adr filename$ )
['] tftp-read catch if ( adr filename$ )
tftp-close -1 throw
then ( size )
tftp-close ( size )
;
headers