Merge branch 'master' of ssh://rom.etherboot.org/pub/scm/gpxe
authorMarty Connor <mdc@etherboot.org>
Mon, 2 Jul 2007 19:36:19 +0000 (15:36 -0400)
committerMarty Connor <mdc@etherboot.org>
Mon, 2 Jul 2007 19:36:19 +0000 (15:36 -0400)
16 files changed:
src/core/async.c [deleted file]
src/core/btext.c
src/core/debug.c
src/core/dev.c
src/core/disk.c
src/core/misc.c
src/core/pcmcia.c
src/core/random.c
src/core/serial.c
src/include/gpxe/icmp6.h
src/include/gpxe/ndp.h
src/net/icmpv6.c
src/proto/igmp.c
src/proto/nfs.c
src/proto/tftm.c [deleted file]
src/proto/tftpcore.c [deleted file]

diff --git a/src/core/async.c b/src/core/async.c
deleted file mode 100644 (file)
index d1ae077..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <gpxe/process.h>
-#include <gpxe/async.h>
-
-/** @file
- *
- * Asynchronous operations
- *
- */
-
-/**
- * Name signal
- *
- * @v signal           Signal number
- * @ret name           Name of signal
- */
-static inline __attribute__ (( always_inline )) const char *
-signal_name ( enum signal signal ) {
-       switch ( signal ) {
-       case SIGCHLD:           return "SIGCHLD";
-       case SIGKILL:           return "SIGKILL";
-       case SIGUPDATE:         return "SIGUPDATE";
-       default:                return "SIG<UNKNOWN>";
-       }
-}
-
-/**
- * Initialise an asynchronous operation
- *
- * @v async            Asynchronous operation
- * @v aop              Asynchronous operation operations to use
- * @v parent           Parent asynchronous operation, or NULL
- * @ret aid            Asynchronous operation ID
- *
- * It is valid to create an asynchronous operation with no parent
- * operation; see async_init_orphan().
- */
-aid_t async_init ( struct async *async, struct async_operations *aop,
-                  struct async *parent ) {
-       static aid_t aid = 1;
-
-       /* Assign identifier.  Negative IDs are used to indicate
-        * errors, so avoid assigning them.
-        */
-       ++aid;
-       aid &= ( ( ~( ( aid_t ) 0 ) ) >> 1 );
-
-       DBGC ( async, "ASYNC %p (type %p) initialising as", async, aop );
-       if ( parent ) {
-               DBGC ( async, " child of ASYNC %p", parent );
-       } else {
-               DBGC ( async, " orphan" );
-       }
-       DBGC ( async, " with ID %ld\n", aid );
-
-       assert ( async != NULL );
-       assert ( aop != NULL );
-
-       /* Add to hierarchy */
-       if ( parent ) {
-               async->parent = parent;
-               list_add ( &async->siblings, &parent->children );
-       }
-       INIT_LIST_HEAD ( &async->children );
-
-       /* Initialise fields */
-       async->rc = -EINPROGRESS;
-       async->completed = 0;
-       async->total = 0;
-       async->aop = aop;
-       async->aid = aid;
-
-       return async->aid;
-}
-
-/**
- * Uninitialise an asynchronous operation
- *
- * @v async            Asynchronous operation
- *
- * Abandon an asynchronous operation without signalling the parent.
- * You may do this only during the period between calling async_init()
- * and returning to the parent for the first time.  It is designed to
- * simplify the error paths of asynchronous operations that themselves
- * spawn further asynchronous operations.
- *
- * An example may help:
- *
- *     int start_something ( ..., struct async *parent ) {
- *         struct my_data_structure *myself;
- *
- *         ... allocate memory for myself ...
- *
- *         async_init ( &myself->async, &my_async_operations, parent );
- *         if ( ( rc = start_child_operation ( ..., &myself->async ) ) != 0 ) {
- *             async_uninit ( &myself->async );
- *             return rc;
- *         }
- *
- *         return 0;
- *     }
- *
- * It is valid to call async_uninit() on an asynchronous operation
- * that has not yet been initialised (i.e. a zeroed-out @c struct @c
- * async).
- */
-void async_uninit ( struct async *async ) {
-
-       assert ( async != NULL );
-
-       if ( async->parent ) {
-               assert ( list_empty ( &async->children ) );
-
-               DBGC ( async, "ASYNC %p uninitialising\n", async );
-               list_del ( &async->siblings );
-       }
-}
-
-/**
- * SIGCHLD 'ignore' handler
- *
- * @v async            Asynchronous operation
- * @v signal           Signal received
- */
-static void async_ignore_sigchld ( struct async *async, enum signal signal ) {
-       aid_t waited_aid;
-
-       assert ( async != NULL );
-       assert ( signal == SIGCHLD );
-
-       /* Reap the child */
-       waited_aid = async_wait ( async, NULL, 0 );
-       assert ( waited_aid >= 0 );
-}
-
-/**
- * SIGUPDATE 'ignore' handler
- *
- * @v async            Asynchronous operation
- * @v signal           Signal received
- */
-static void async_ignore_sigupdate ( struct async *async,
-                                    enum signal signal ) {
-       struct async *child;
-
-       assert ( async != NULL );
-       assert ( signal == SIGUPDATE );
-
-       async_signal_children ( async, signal );
-       async->completed = 0;
-       async->total = 0;
-       list_for_each_entry ( child, &async->children, siblings ) {
-               async->completed += child->completed;
-               async->total += child->total;
-       }
-}
-
-/**
- * 'Ignore' signal handler
- *
- * @v async            Asynchronous operation
- * @v signal           Signal received
- */
-void async_ignore_signal ( struct async *async, enum signal signal ) {
-
-       DBGC ( async, "ASYNC %p using ignore handler for %s\n",
-              async, signal_name ( signal ) );
-
-       assert ( async != NULL );
-
-       switch ( signal ) {
-       case SIGCHLD:
-               async_ignore_sigchld ( async, signal );
-               break;
-       case SIGUPDATE:
-               async_ignore_sigupdate ( async, signal );
-               break;
-       case SIGKILL:
-       default:
-               /* Nothing to do */
-               break;
-       }
-}
-
-/**
- * Default signal handler
- *
- * @v async            Asynchronous operation
- * @v signal           Signal received
- */
-static void async_default_signal ( struct async *async, enum signal signal ) {
-
-       DBGC ( async, "ASYNC %p using default handler for %s\n",
-              async, signal_name ( signal ) );
-
-       assert ( async != NULL );
-
-       switch ( signal ) {
-       case SIGCHLD:
-       case SIGKILL:
-       case SIGUPDATE:
-       default:
-               /* Nothing to do */
-               break;
-       }
-}
-
-/**
- * Send signal to asynchronous operation
- *
- * @v async            Asynchronous operation
- * @v signal           Signal to send
- */
-void async_signal ( struct async *async, enum signal signal ) {
-       signal_handler_t handler;
-
-       DBGC ( async, "ASYNC %p receiving %s\n",
-              async, signal_name ( signal ) );
-
-       assert ( async != NULL );
-       assert ( async->aop != NULL );
-       assert ( signal < SIGMAX );
-
-       handler = async->aop->signal[signal];
-       if ( handler ) {
-               /* Use the asynchronous operation's signal handler */
-               handler ( async, signal );
-       } else {
-               /* Use the default handler */
-               async_default_signal ( async, signal );
-       }
-}
-
-/**
- * Send signal to all child asynchronous operations
- *
- * @v async            Asynchronous operation
- * @v signal           Signal to send
- */
-void async_signal_children ( struct async *async, enum signal signal ) {
-       struct async *child;
-       struct async *tmp;
-
-       assert ( async != NULL );
-
-       list_for_each_entry_safe ( child, tmp, &async->children, siblings ) {
-               async_signal ( child, signal );
-       }
-}
-
-/**
- * Reap default handler
- *
- * @v async            Asynchronous operation
- */
-static void async_reap_default ( struct async *async ) {
-
-       DBGC ( async, "ASYNC %p ignoring REAP\n", async );
-
-       assert ( async != NULL );
-
-       /* Nothing to do */
-}
-
-/**
- * Reap asynchronous operation
- *
- * @v async            Asynchronous operation
- *
- * Note that the asynchronous operation should have been freed by
- * calling this function; you may not dereference @c async after this
- * call.
- */
-static void async_reap ( struct async *async ) {
-
-       DBGC ( async, "ASYNC %p being reaped, exit status %d (%s)\n",
-              async, async->rc, strerror ( async->rc ) );
-
-       assert ( async != NULL );
-       assert ( async->aop != NULL );
-       assert ( list_empty ( &async->children ) );
-
-       /* Unlink from hierarchy */
-       if ( async->parent )
-               list_del ( &async->siblings );
-       async->parent = NULL;
-
-       /* Release all resources */
-       if ( async->aop->reap ) {
-               async->aop->reap ( async );
-       } else {
-               async_reap_default ( async );
-       }
-}
-
-/**
- * Mark asynchronous operation as complete
- *
- * @v async            Asynchronous operation
- * @v rc               Return status code
- *
- * An asynchronous operation should call this once it has completed.
- * After calling async_done(), it must be prepared to be reaped by
- * having its reap() method called.
- */
-void async_done ( struct async *async, int rc ) {
-       struct async *child;
-       struct async *tmp;
-
-       DBGC ( async, "ASYNC %p completing with status %d (%s)\n",
-              async, rc, strerror ( rc ) );
-
-       assert ( async != NULL );
-       assert ( async->parent != NULL );
-       assert ( rc != -EINPROGRESS );
-
-       /* Store return status code */
-       async->rc = rc;
-
-       /* Disown all of our children */
-       list_for_each_entry_safe ( child, tmp, &async->children, siblings ) {
-               DBGC ( async, "ASYNC %p disowning child ASYNC %p\n",
-                      async, child );
-               list_del ( &child->siblings );
-               child->parent = NULL;
-       }
-
-       /* Send SIGCHLD to parent.  If we don't have a parent then we
-        * have to take care of our own funeral arrangements.
-        */
-       if ( async->parent ) {
-               async_signal ( async->parent, SIGCHLD );
-       } else {
-               async_reap ( async );
-       }
-}
-
-/**
- * Wait for any child asynchronous operation to complete
- * 
- * @v child            Child asynchronous operation
- * @v rc               Child exit status to fill in, or NULL
- * @v block            Block waiting for child operation to complete
- * @ret aid            Asynchronous operation ID, or -1 on error
- */
-aid_t async_wait ( struct async *async, int *rc, int block ) {
-       struct async *child;
-       aid_t child_aid;
-       int dummy_rc;
-
-       DBGC ( async, "ASYNC %p performing %sblocking wait%s\n", async,
-              ( block ? "" : "non-" ), ( rc ? "" : " (ignoring status)" ) );
-
-       assert ( async != NULL );
-
-       /* Avoid multiple tests for "if ( rc )" */
-       if ( ! rc )
-               rc = &dummy_rc;
-
-       while ( 1 ) {
-
-               /* Return immediately if we have no children */
-               if ( list_empty ( &async->children ) ) {
-                       DBGC ( async, "ASYNC %p has no more children\n",
-                              async );
-                       *rc = -ECHILD;
-                       return -1;
-               }
-
-               /* Look for a completed child */
-               list_for_each_entry ( child, &async->children, siblings ) {
-                       if ( child->rc == -EINPROGRESS )
-                               continue;
-
-                       /* Found a completed child */
-                       *rc = child->rc;
-                       child_aid = child->aid;
-
-                       DBGC ( async, "ASYNC %p reaping child ASYNC %p "
-                              "(ID %ld)\n", async, child, child_aid );
-
-                       /* Reap the child and return */
-                       async_reap ( child );
-                       return child_aid;
-               }
-
-               /* Return immediately if non-blocking */
-               if ( ! block ) {
-                       *rc = -EINPROGRESS;
-                       return -1;
-               }
-
-               /* Allow processes to run */
-               step();
-       }
-}
-
-/**
- * Wait for any child asynchronous operation to complete, with progress bar
- * 
- * @v child            Child asynchronous operation
- * @v rc               Child exit status to fill in, or NULL
- * @ret aid            Asynchronous operation ID, or -1 on error
- */
-aid_t async_wait_progress ( struct async *async, int *rc ) {
-       struct async *child;
-       long last_progress = -1;
-       long progress;
-       aid_t child_aid;
-
-       do {
-               step();
-               async_signal ( async, SIGUPDATE );
-               if ( async->total ) {
-                       progress = ( async->completed / (async->total / 100) );
-                       if ( progress != last_progress )
-                               printf ( "\rProgress: %d%%", progress );
-                       last_progress = progress;
-               }
-               child_aid = async_wait ( async, rc, 0 );
-       } while ( *rc == -EINPROGRESS );
-
-       printf ( "\n" );
-       return child_aid;
-}
-
-/**
- * Default asynchronous operations
- *
- * The default is to ignore SIGCHLD (i.e. to automatically reap
- * children) and to use the default handler (i.e. do nothing) for all
- * other signals.
- */
-struct async_operations default_async_operations = {
-       .signal = {
-               [SIGCHLD]       = SIG_IGN,
-               [SIGUPDATE]     = SIG_IGN,
-       },
-};
-
-/**
- * Default asynchronous operations for orphan asynchronous operations
- *
- * The default for orphan asynchronous operations is to do nothing for
- * SIGCHLD (i.e. to not automatically reap children), on the
- * assumption that you're probably creating the orphan solely in order
- * to async_wait() on it.
- */
-struct async_operations orphan_async_operations = {
-       .signal = {
-               [SIGCHLD]       = SIG_DFL,
-               [SIGUPDATE]     = SIG_IGN,
-       },
-};
index 409c429..6e1a29e 100644 (file)
@@ -1,3 +1,5 @@
+#if 0
+
 /*
  * Procedures for drawing on the screen early on in the boot process.
  *
@@ -5037,3 +5039,5 @@ static const unsigned char vga_font[cmapsz] BTDATA = {
        0x00, /* 00000000 */
 #endif
 };
+
+#endif
index 4754bfd..d72b3df 100644 (file)
@@ -1,3 +1,4 @@
+#include <stdio.h>
 #include <stdint.h>
 #include <stdarg.h>
 #include <io.h>
index 541a9eb..582edf8 100644 (file)
@@ -1,6 +1,7 @@
-#include "etherboot.h"
-#include "stddef.h"
-#include "dev.h"
+#include <stdio.h>
+#include <etherboot.h>
+#include <stddef.h>
+#include <dev.h>
 
 /*
  * Each bus driver defines several methods, which are described in
index 2ccd5ff..415fdec 100644 (file)
@@ -1,5 +1,5 @@
-#include "etherboot.h"
-#include "disk.h"
+#include <etherboot.h>
+#include <disk.h>
 
 #warning "disk.c is currently broken"
 #if 0
index e214a62..5839913 100644 (file)
@@ -2,9 +2,10 @@
 MISC Support Routines
 **************************************************************************/
 
-#include "etherboot.h"
-#include "console.h"
+#include <etherboot.h>
+#include <console.h>
 #include <stdlib.h>
+#include <stdio.h>
 
 /**************************************************************************
 IPCHKSUM - Checksum IP Header
index c15fe9c..53d4541 100644 (file)
@@ -1,3 +1,5 @@
+#if 0
+
 /*
  *     pcmcia.c
  *
  *     at some point. If there's anything obvious or better, not-so-obvious,
  *     please contact me by e-mail: anselm (AT) hoffmeister (DOT) be   *THANKS*
  */
-#include "pcmcia.h"
-#include "i82365.h"
+#include <stdio.h>
+#include <pcmcia.h>
+#include <i82365.h>
 #define CODE_STATUS "alpha"
 #define        CODE_VERSION "0.1.3"
-#include "pcmcia-opts.h"
-#include "console.h"
+#include <pcmcia-opts.h>
+#include <console.h>
 #include <gpxe/init.h>
 
 int    sockets; /* AHTODO: Phase this out! */
@@ -118,7 +121,7 @@ static void pcmcia_init_all(void) {
                                printf ( "]\nHighest config available is %d\n", uc[2*(ui+3)] );
                                m = uc[2*(ui+2)];
                                pccsock[i].configoffset = 0;
-                               for ( j = 0; j <= m & 3; ++j ) {
+                               for ( j = 0; j <= (m & 3); ++j ) {
                                        pccsock[i].configoffset += uc[2*(ui+4+j)] << (8*j);
                                }
                                pccsock[i].rmask0 = 0;
@@ -262,3 +265,5 @@ static void pcmcia_shutdown_all(void) {
 }
 
 INIT_FN ( INIT_PCMCIA, pcmcia_init_all, NULL, pcmcia_shutdown_all );
+
+#endif
index c15bb6d..0d914c9 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <stdlib.h>
+#include <etherboot.h>
 
 static int32_t rnd_seed = 0;
 
index d082748..6304037 100644 (file)
@@ -213,7 +213,7 @@ static void serial_init ( void ) {
                /* rx buffer reg
                 * throw away (unconditionally the first time)
                 */
-               uart_readb(UART_BASE + UART_RBR);
+               (void) uart_readb(UART_BASE + UART_RBR);
                /* line status reg */
                status = uart_readb(UART_BASE + UART_LSR);
        } while(status & UART_LSR_DR);
index 3521036..76aaddf 100644 (file)
@@ -32,7 +32,7 @@ struct neighbour_solicit {
        /* "Compulsory" options */
        uint8_t opt_type;
        uint8_t opt_len;
-#warning hack alert
+  /* FIXME:  hack alert */
        uint8_t opt_ll_addr[6];
 };
 
@@ -45,7 +45,7 @@ struct neighbour_advert {
        struct in6_addr target;
        uint8_t opt_type;
        uint8_t opt_len;
-#warning hack alert
+  /* FIXME:  hack alert */
        uint8_t opt_ll_addr[6];
 };
 
index e3711b5..2eae295 100644 (file)
@@ -16,7 +16,6 @@
 #define NDP_STATE_PROBE 4
 #define NDP_STATE_STALE 5
 
-static struct ndp_entry * ndp_find_entry ( struct in6_addr *in6 );
 int ndp_resolve ( struct net_device *netdev, struct in6_addr *src,
                  struct in6_addr *dest, void *dest_ll_addr );
 int ndp_process_advert ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
index da73892..69824c5 100644 (file)
@@ -72,7 +72,7 @@ int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src __unuse
  * @v st_dest  Destination address
  */
 static int icmp6_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
-                     struct sockaddr_tcpip *st_dest ) {
+                     struct sockaddr_tcpip *st_dest, __unused uint16_t pshdr_csum ) {
        struct icmp6_header *icmp6hdr = iobuf->data;
 
        /* Sanity check */
index 4d4df90..d61f6c4 100644 (file)
@@ -3,11 +3,11 @@
  *
  */
 
-#include "ip.h"
-#include "igmp.h"
-#include "background.h"
-#include "nic.h"
-#include "etherboot.h"
+#include <ip.h>
+#include <igmp.h>
+#include <background.h>
+#include <nic.h>
+#include <etherboot.h>
 
 static unsigned long last_igmpv1 = 0;
 static struct igmptable_t igmptable[MAX_IGMP];
@@ -50,8 +50,7 @@ static void send_igmp_reports ( unsigned long now ) {
                igmp.igmp.chksum = ipchksum ( &igmp.igmp,
                                              sizeof ( igmp.igmp ) );
                ip_transmit ( sizeof ( igmp ), &igmp );
-               DBG ( "IGMP sent report to %@\n",
-                     igmp.igmp.group.s_addr );
+               DBG ( "IGMP sent report to %s\n", inet_ntoa ( igmp.igmp.group ) );
                /* Don't send another igmp report until asked */
                igmptable[i].time = 0;
        }
@@ -84,7 +83,7 @@ static void process_igmp ( unsigned long now, unsigned short ptype __unused,
                        interval = ( igmp->response_time * TICKS_PER_SEC ) /10;
                }
                
-               DBG ( "IGMP received query for %@\n", igmp->group.s_addr );
+               DBG ( "IGMP received query for %s\n", inet_ntoa ( igmp->group ) );
                for ( i = 0 ; i < MAX_IGMP ; i++ ) {
                        uint32_t group = igmptable[i].group.s_addr;
                        if ( ( group == 0 ) ||
@@ -101,7 +100,8 @@ static void process_igmp ( unsigned long now, unsigned short ptype __unused,
        if ( ( ( igmp->type == IGMPv1_REPORT ) ||
               ( igmp->type == IGMPv2_REPORT ) ) &&
             ( ip->dest.s_addr == igmp->group.s_addr ) ) {
-               DBG ( "IGMP received report for %@\n", igmp->group.s_addr);
+               DBG ( "IGMP received report for %s\n", 
+                     inet_ntoa ( igmp->group ) );
                for ( i = 0 ; i < MAX_IGMP ; i++ ) {
                        if ( ( igmptable[i].group.s_addr ==
                               igmp->group.s_addr ) &&
@@ -142,7 +142,7 @@ void leave_group ( int slot ) {
                igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
                igmp.igmp.chksum = ipchksum ( &igmp.igmp, sizeof ( igmp ) );
                ip_transmit ( sizeof ( igmp ), &igmp );
-               DBG ( "IGMP left group %@\n", igmp.igmp.group.s_addr );
+               DBG ( "IGMP left group %s\n", inet_ntoa ( igmp.igmp.group ) );
        }
        memset ( &igmptable[slot], 0, sizeof ( igmptable[0] ) );
 }
index c700ed6..2743287 100644 (file)
@@ -49,7 +49,7 @@ static void rpc_printerror(struct rpc_t *rpc)
            rpc->u.reply.astatus) {
                /* rpc_printerror() is called for any RPC related error,
                 * suppress output if no low level RPC error happened.  */
-               DBG("RPC error: (%d,%d,%d)\n", ntohl(rpc->u.reply.rstatus),
+               DBG("RPC error: (%ld,%ld,%ld)\n", ntohl(rpc->u.reply.rstatus),
                    ntohl(rpc->u.reply.verifier),
                    ntohl(rpc->u.reply.astatus));
        }
@@ -503,14 +503,14 @@ static int nfs ( char *url __unused, struct sockaddr_in *server,
        mount_server.sin_addr = nfs_server.sin_addr = server->sin_addr;
        mount_server.sin_port = rpc_lookup(server, PROG_MOUNT, 1, sport);
        if ( ! mount_server.sin_port ) {
-               DBG ( "Cannot get mount port from %!:%d\n",
-                     server->sin_addr.s_addr, server->sin_port );
+               DBG ( "Cannot get mount port from %s:%d\n",
+                     inet_ntoa ( server->sin_addr ), server->sin_port );
                return 0;
        }
        nfs_server.sin_port = rpc_lookup(server, PROG_NFS, 2, sport);
        if ( ! mount_server.sin_port ) {
-               DBG ( "Cannot get nfs port from %!:%d\n",
-                     server->sin_addr.s_addr, server->sin_port );
+               DBG ( "Cannot get nfs port from %s:%d\n",
+                     inet_ntoa ( server->sin_addr ), server->sin_port );
                return 0;
        }
 
diff --git a/src/proto/tftm.c b/src/proto/tftm.c
deleted file mode 100644 (file)
index fb011c6..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-#include "etherboot.h"
-#include "proto.h"
-#include "errno.h"
-#include "tftp.h"
-#include "tftpcore.h"
-
-/** @file
- *
- * TFTM protocol
- *
- * TFTM is a protocol defined in RFC2090 as a multicast extension to
- * TFTP.
- */
-
-static inline int tftm_process_opts ( struct tftp_state *state,
-                                     struct tftp_oack *oack ) {
-       struct in_addr old_mcast_addr = state->multicast.sin_addr;
-
-       if ( ! tftp_process_opts ( state, oack ) )
-               return 0;
-
-       if ( old_mcast_addr.s_addr != state->multicast.sin_addr.s_addr ) {
-               if ( old_mcast_addr.s_addr ) {
-                       DBG ( "TFTM: Leaving multicast group %@\n",
-                             old_mcast_addr.s_addr );
-                       leave_group ( IGMP_SERVER );
-               }
-               DBG ( "TFTM: Joining multicast group %@\n",
-                     state->multicast.sin_addr.s_addr );
-               join_group ( IGMP_SERVER, state->multicast.sin_addr.s_addr );
-       }
-
-       DBG ( "TFTM: I am a %s client\n",
-             ( state->master ? "master" : "slave" ) );
-
-       return 1;
-}
-
-
-static inline int tftm_process_data ( struct tftp_state *state,
-                                     struct tftp_data *data,
-                                     struct buffer *buffer ) {
-       unsigned int blksize;
-       off_t offset;
-
-       /* Calculate block size and offset within file */
-       blksize = ( ntohs ( data->udp.len )
-                   + offsetof ( typeof ( *data ), udp )
-                   - offsetof ( typeof ( *data ), data ) );
-       offset = ( ntohs ( data->block ) - 1 ) * state->blksize;
-
-       /* Check for oversized block */
-       if ( blksize > state->blksize ) {
-               DBG ( "TFTM: oversized block size %d (max %d)\n",
-                     blksize, state->blksize );
-               errno = PXENV_STATUS_TFTP_INVALID_PACKET_SIZE;
-               return 0;
-       }
-
-       /* Place block in the buffer */
-       if ( ! fill_buffer ( buffer, data->data, offset, blksize ) ) {
-               DBG ( "TFTM: could not place data in buffer: %m\n" );
-               return 0;
-       }
-
-       /* If this is the last block, record the filesize (in case the
-        * server didn't supply a tsize option.
-        */
-       if ( blksize < state->blksize ) {
-               state->tsize = offset + blksize;
-       }
-
-       /* Record the last received block */
-       state->block = ntohs ( data->block );
-
-       return 1;
-}
-
-
-static inline int tftm_next ( struct tftp_state *state,
-                             union tftp_any **reply,
-                             struct buffer *buffer ) {
-       long listen_timeout;
-
-       listen_timeout = rfc2131_sleep_interval ( TIMEOUT, MAX_TFTP_RETRIES );
-
-       /* If we are not the master client, just listen for the next
-        * packet
-        */
-       if ( ! state->master ) {
-               if ( tftp_get ( state, listen_timeout, reply ) ) {
-                       /* Heard a non-error packet */
-                       return 1;
-               }
-               if ( *reply ) {
-                       /* Received an error packet */
-                       return 0;
-               }
-               /* Didn't hear anything; try prodding the server */
-               state->master = 1;
-       }
-       /* We are the master client; trigger the next packet
-        * that we want
-        */
-       state->block = buffer->fill / state->blksize;
-       return tftp_ack ( state, reply );
-}
-
-/**
- * Download a file via TFTM
- *
- * @v server                           TFTP server
- * @v file                             File name
- * @v buffer                           Buffer into which to load file
- * @ret True                           File was downloaded successfully
- * @ret False                          File was not downloaded successfully
- * @err #PXENV_STATUS_TFTP_UNKNOWN_OPCODE Unknown type of TFTP block received
- * @err other                          As returned by tftp_open()
- * @err other                          As returned by tftp_process_opts()
- * @err other                          As returned by tftp_ack()
- * @err other                          As returned by tftp_process_data()
- *
- * Download a file from a TFTP server into the specified buffer using
- * the TFTM protocol.
- */
-static int tftm ( char *url __unused, struct sockaddr_in *server, char *file,
-                 struct buffer *buffer ) {
-       struct tftp_state state;
-       union tftp_any *reply;
-       int rc = 0;
-
-       /* Initialise TFTP state */
-       memset ( &state, 0, sizeof ( state ) );
-       state.server = *server;
-
-       /* Start as the master.  This means that if the TFTP server
-        * doesn't actually support multicast, we'll still ACK the
-        * packets and it should all proceed as for a normal TFTP
-        * connection.
-        */
-       state.master = 1;
-       
-       /* Open the file */
-       if ( ! tftp_open ( &state, file, &reply, 1 ) ) {
-               DBG ( "TFTM: could not open %@:%d/%s : %m\n",
-                     server->sin_addr.s_addr, server->sin_port, file );
-               return 0;
-       }
-
-       /* Fetch file, a block at a time */
-       while ( 1 ) {
-               twiddle();
-               /* Process the current packet */
-               switch ( ntohs ( reply->common.opcode ) ) {
-               case TFTP_OACK:
-                       /* Options can be received at any time */
-                       if ( ! tftm_process_opts ( &state, &reply->oack ) ) {
-                               DBG ( "TFTM: failed to process OACK: %m\n" );
-                               tftp_error ( &state, TFTP_ERR_BAD_OPTS, NULL );
-                               goto out;
-                       }
-                       break;
-               case TFTP_DATA:
-                       if ( ! tftm_process_data ( &state, &reply->data,
-                                                  buffer ) ) {
-                               DBG ( "TFTM: failed to process DATA: %m\n" );
-                               tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
-                                            NULL );
-                               goto out;
-                       }
-                       break;
-               default:
-                       DBG ( "TFTM: unexpected packet type %d\n",
-                             ntohs ( reply->common.opcode ) );
-                       errno = PXENV_STATUS_TFTP_UNKNOWN_OPCODE;
-                       tftp_error ( &state, TFTP_ERR_ILLEGAL_OP, NULL );
-                       goto out;
-               }
-               /* If we know the filesize, and we have all the data, stop */
-               if ( state.tsize && ( buffer->fill == state.tsize ) )
-                       break;
-               /* Fetch the next packet */
-               if ( ! tftm_next ( &state, &reply, buffer ) ) {
-                       DBG ( "TFTM: could not get next block: %m\n" );
-                       if ( ! reply ) {
-                               tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
-                                            NULL );
-                       }
-                       goto out;
-               }
-       }
-
-       /* ACK the final packet, as a courtesy to the server */
-       tftp_ack_nowait ( &state );
-
-       rc = 1;
- out:
-       if ( state.multicast.sin_addr.s_addr ) {
-               leave_group ( IGMP_SERVER );
-       }
-       return rc;
-}
-
-static struct protocol tftm_protocol __protocol = {
-       .name = "x-tftm",
-       .default_port = TFTP_PORT,
-       .load = tftm,
-};
diff --git a/src/proto/tftpcore.c b/src/proto/tftpcore.c
deleted file mode 100644 (file)
index c7673bd..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-#include "tftp.h"
-#include "old_tcp.h" /* for struct tcphdr */
-#include "errno.h"
-#include "etherboot.h"
-#include "tftpcore.h"
-
-/** @file */
-
-/**
- * await_reply() filter for TFTP packets
- *
- * @v ptr                              Pointer to a struct tftp_state
- * @v tftp_state::server::sin_addr     TFTP server IP address
- * @v tftp_state::lport                        Client UDP port
- * @v tftp_state::multicast::sin_addr  Multicast IP address, or 0.0.0.0
- * @v tftp_state::multicast::sin_port  Multicast UDP port, or 0
- * @v ip                               IP header
- * @v udp                              UDP header
- * @ret True                           This is our TFTP packet
- * @ret False                          This is not one of our TFTP packets
- *
- * Wait for a TFTP packet that is part of the current connection
- * (i.e. comes from the TFTP server, has the correct destination port,
- * and is addressed either to our IP address and UDP port, or to our
- * multicast listening address and UDP port).
- *
- * Use await_tftp() in code such as
- *
- * @code
- *
- * if ( await_reply ( await_tftp, 0, &tftp_state, timeout ) ) {
- *     ...
- * }
- *
- * @endcode
- */
-static int await_tftp ( int ival __unused, void *ptr,
-                       unsigned short ptype __unused, struct iphdr *ip,
-                       struct udphdr *udp, struct tcphdr *tcp __unused ) {
-       struct tftp_state *state = ptr;
-
-       /* Must have valid UDP (and, therefore, also IP) headers */
-       if ( ! udp ) {
-               DBG2 ( "TFTPCORE: not UDP\n" );
-               return 0;
-       }
-       /* Packet must come from the TFTP server */
-       if ( ip->src.s_addr != state->server.sin_addr.s_addr ) {
-               DBG2 ( "TFTPCORE: from %@, not from TFTP server %@\n",
-                      ip->src.s_addr, state->server.sin_addr.s_addr );
-               return 0;
-       }
-       /* Packet may be addressed to our IP address and unicast UDP
-        * port
-        */
-       if ( ( ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr ) &&
-            ( ntohs ( udp->dest ) == state->lport ) ) {
-               return 1;
-       }
-       /* Packet may be addressed to our multicast IP address and UDP
-        * port, if we have one
-        */
-       if ( ( state->multicast.sin_addr.s_addr ) && 
-            ( ip->dest.s_addr == state->multicast.sin_addr.s_addr ) &&
-            ( ntohs ( udp->dest ) == state->multicast.sin_port ) ) {
-               return 1;
-       }
-       DBG2 ( "TFTPCORE: to %@:%d, not to %@:%d (or %@:%d)\n",
-              ip->dest.s_addr, ntohs ( udp->dest ),
-              arptable[ARP_CLIENT].ipaddr.s_addr, state->lport,
-              state->multicast.sin_addr.s_addr, state->multicast.sin_port );
-       return 0;
-}
-
-/**
- * Retrieve a TFTP packet
- *
- * @v state                            TFTP transfer state
- * @v tftp_state::server::sin_addr     TFTP server IP address
- * @v tftp_state::lport                        Client UDP port
- * @v tftp_state::multicast::sin_addr  Multicast IP address, or 0.0.0.0
- * @v tftp_state::multicast::sin_port  Multicast UDP port, or 0
- * @v timeout                          Time to wait for a response
- * @ret True                           Received a non-error response
- * @ret False                          Received error response / no response
- * @ret *reply                         The server's response, if any
- * @err #PXENV_STATUS_TFTP_READ_TIMEOUT        No response received in time
- * @err other                          As set by tftp_set_errno()
- *
- * Retrieve the next packet sent by the TFTP server, if any is sent
- * within the specified timeout period.  The packet is returned via
- * #reply.  If no packet is received within the timeout period, a NULL
- * value will be stored in #reply.
- *
- * If the response from the server is a TFTP ERROR packet, tftp_get()
- * will return False and #errno will be set accordingly.
- *
- * You can differentiate between "received no response" and "received
- * an error response" by checking #reply; if #reply is NULL then no
- * response was received.
- */
-int tftp_get ( struct tftp_state *state, long timeout,
-              union tftp_any **reply ) {
-
-       *reply = NULL;
-
-       if ( ! await_reply ( await_tftp, 0, state, timeout ) ) {
-               errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
-               return 0;
-       }
-
-       *reply = ( union tftp_any * ) &nic.packet[ETH_HLEN];
-       DBG ( "TFTPCORE: got reply (type %d)\n",
-             ntohs ( (*reply)->common.opcode ) );
-       if ( ntohs ( (*reply)->common.opcode ) == TFTP_ERROR ){
-               tftp_set_errno ( &(*reply)->error );
-               return 0;
-       }
-       return 1;
-}
-
-/**
- * Issue a TFTP open request (RRQ)
- *
- * @v state                            TFTP transfer state
- * @v tftp_state::server::sin_addr     TFTP server IP address
- * @v tftp_state::server::sin_port     TFTP server UDP port, or 0
- * @v tftp_state::lport                        Client UDP port, or 0
- * @v tftp_state::multicast::sin_addr  Multicast IP address, or 0.0.0.0
- * @v tftp_state::multicast::sin_port  Multicast UDP port, or 0
- * @v tftp_state::blksize              Requested blksize, or 0
- * @v filename                         File name
- * @v multicast                                Enable/disable rfc2090 multicast TFTP
- * @ret True                           Received a non-error response
- * @ret False                          Received error response / no response
- * @ret tftp_state::server::sin_port   TFTP server UDP port
- * @ret tftp_state::lport              Client UDP port
- * @ret tftp_state::blksize            Always #TFTP_DEFAULT_BLKSIZE
- * @ret *reply                         The server's response, if any
- * @err #PXENV_STATUS_TFTP_OPEN_TIMEOUT        TFTP open timed out
- * @err other                          As returned by udp_transmit()
- * @err other                          As set by tftp_set_errno()
- *
- * Send a TFTP/TFTM/MTFTP RRQ (read request) to a TFTP server, and
- * return the server's reply (which may be an OACK, DATA or ERROR
- * packet).  The server's reply will not be acknowledged, or processed
- * in any way.
- *
- * If tftp_state::server::sin_port is 0, the standard TFTP server port
- * (#TFTP_PORT) will be used.
- *
- * If tftp_state::lport is 0, the standard mechanism of
- * using a new, unique port number for each TFTP request will be used.
- * 
- * If tftp_state::multicast::sin_addr is not 0.0.0.0, it (and
- * tftp_state::multicast::sin_port) will be used as a multicast
- * listening address for replies from the TFTP server.
- *
- * For the various different types of TFTP server, you should treat
- * tftp_state::lport and tftp_state::multicast as follows:
- *
- *   - Standard TFTP server: set tftp_state::lport to 0,
- *     tftp_state::multicast::sin_addr to 0.0.0.0 and
- *     tftp_state::multicast::sin_port to 0.  tftp_open() will set
- *     tftp_state::lport to the assigned local UDP port.
- *
- *   - TFTM server: set tftp_state::lport to 0,
- *     tftp_state::multicast::sin_addr to 0.0.0.0 and
- *     tftp_state::multicast::sin_port to 0.  tftp_open() will set
- *     tftp_state::lport to the assigned local UDP port.  (Your call
- *     to tftp_process_opts() will then overwrite both
- *     tftp_state::multicast::sin_addr and
- *     tftp_state::multicast::sin_port with the values specified in
- *     the OACK packet.)
- *
- *   - MTFTP server: set tftp_state::multicast::sin_addr to the
- *     multicast address and both tftp_state::lport and
- *     tftp_state::multicast::sin_port to the multicast port (both of
- *     which must be previously known, e.g. provided by a DHCP
- *     server).  tftp_open() will not alter these values.
- *
- * If tftp_state::blksize is 0, the maximum blocksize
- * (#TFTP_MAX_BLKSIZE) will be requested.
- *
- * On exit, tftp_state::blksize will always contain
- * #TFTP_DEFAULT_BLKSIZE, since this is the blocksize value that must
- * be assumed until the OACK packet is processed (by a subsequent call
- * to tftp_process_opts()).
- *
- * tftp_state::server::sin_port will be set to the UDP port from which
- * the server's response originated.  This may or may not be the port
- * to which the open request was sent.
- *
- * The options "blksize" and "tsize" will always be appended to a TFTP
- * open request.  The option "multicast" will be appended to the
- * request if #multicast is True.  Servers that do not understand any
- * of these options should simply ignore them.
- *
- * tftp_open() will not automatically join or leave multicast groups;
- * the caller is responsible for calling join_group() and
- * leave_group() at appropriate times.
- *
- * If the response from the server is a TFTP ERROR packet, tftp_open()
- * will return False and #errno will be set accordingly.
- */
-int tftp_open ( struct tftp_state *state, const char *filename,
-               union tftp_any **reply, int multicast ) {
-       static unsigned short lport = 2000; /* local port */
-       int fixed_lport;
-       struct tftp_rrq rrq;
-       char *p;
-       unsigned int rrqlen;
-       int retry;
-
-       /* Flush receive queue */
-       rx_qdrain();
-
-       /* Default to blksize of TFTP_MAX_BLKSIZE if none specified */
-       if ( ! state->blksize )
-               state->blksize = TFTP_MAX_BLKSIZE;
-
-       /* Use default TFTP server port if none specified */
-       if ( ! state->server.sin_port )
-               state->server.sin_port = TFTP_PORT;
-
-       /* Determine whether or not to use lport */
-       fixed_lport = state->lport;
-
-       /* Set up RRQ */
-       rrq.opcode = htons ( TFTP_RRQ );
-       p = rrq.data;
-       p += sprintf ( p, "%s%coctet%cblksize%c%d%ctsize%c0",
-                      filename, 0, 0, 0, state->blksize, 0, 0 ) + 1;
-       if ( multicast ) {
-               p += sprintf ( p, "multicast%c", 0 ) + 1;
-       }
-       rrqlen = ( p - ( char * ) &rrq );
-
-       /* Set negotiated blksize to default value */
-       state->blksize = TFTP_DEFAULT_BLKSIZE;
-       
-       /* Nullify received packet pointer */
-       *reply = NULL;
-
-       /* Transmit RRQ until we get a response */
-       for ( retry = 0 ; retry < MAX_TFTP_RETRIES ; retry++ ) {
-               long timeout = rfc2131_sleep_interval ( TIMEOUT, retry );
-
-               /* Set client UDP port, if not already fixed */
-               if ( ! fixed_lport )
-                       state->lport = ++lport;
-               
-               /* Send the RRQ */
-               DBG ( "TFTPCORE: requesting %@:%d/%s from port %d\n",
-                     state->server.sin_addr.s_addr, state->server.sin_port,
-                     rrq.data, state->lport );
-               if ( ! udp_transmit ( state->server.sin_addr.s_addr,
-                                     state->lport, state->server.sin_port,
-                                     rrqlen, &rrq ) )
-                       return 0;
-               
-               /* Wait for response */
-               if ( tftp_get ( state, timeout, reply ) ) {
-                       /* We got a non-error response */
-                       state->server.sin_port
-                               = ntohs ( (*reply)->common.udp.src );
-                       DBG ( "TFTP server is at %@:%d\n",
-                             state->server.sin_addr.s_addr,
-                             state->server.sin_port );
-                       return 1;
-               }
-               if ( *reply ) {
-                       /* We got an error response; abort */
-                       return 0;
-               }
-       }
-
-       DBG ( "TFTPCORE: open request timed out\n" );
-       errno = PXENV_STATUS_TFTP_OPEN_TIMEOUT;
-       return 0;
-}
-
-/**
- * Process a TFTP OACK packet
- *
- * @v state                            TFTP transfer state
- * @v oack                             The TFTP OACK packet
- * @ret True                           Options were processed successfully
- * @ret False                          Options were not processed successfully
- * @ret tftp_state::blksize            Negotiated blksize
- * @ret tftp_state::tsize              File size (if known), or 0
- * @ret tftp_state::multicast::sin_addr        Multicast IP address, or 0.0.0.0
- * @ret tftp_state::multicast::sin_port        Multicast UDP port, or 0
- * @ret tftp_state::master             Client is master
- * @err EINVAL                         An invalid option value was encountered
- *
- * Process the options returned by the TFTP server in an rfc2347 OACK
- * packet.  The options "blksize" (rfc2348), "tsize" (rfc2349) and
- * "multicast" (rfc2090) are recognised and processed; any other
- * options are silently ignored.
- *
- * Where an option is not present in the OACK packet, the
- * corresponding field(s) in #state will be left unaltered.
- *
- * Calling tftp_process_opts() does not send an acknowledgement for
- * the OACK packet; this is the responsibility of the caller.
- *
- * @note If the "blksize" option is not present, tftp_state::blksize
- * will @b not be implicitly set to #TFTP_DEFAULT_BLKSIZE.  However,
- * since tftp_open() always sets tftp_state::blksize to
- * #TFTP_DEFAULT_BLKSIZE before returning, you probably don't need to
- * worry about this.
- */
-int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
-       const char *p;
-       const char *end;
-
-       DBG ( "TFTPCORE: processing OACK\n" );
-
-       /* End of options */
-       end = ( ( char * ) &oack->udp ) + ntohs ( oack->udp.len );
-
-       /* Only possible error */
-       errno = EINVAL;
-
-       for ( p = oack->data ; p < end ; ) {
-               if ( strcasecmp ( "blksize", p ) == 0 ) {
-                       p += 8;
-                       state->blksize = strtoul ( p, &p, 10 );
-                       if ( *p ) {
-                               DBG ( "TFTPCORE: garbage \"%s\" "
-                                     "after blksize\n", p );
-                               return 0;
-                       }
-                       p++;
-                       DBG ( "TFTPCORE: got blksize %d\n", state->blksize );
-               } else if ( strcasecmp ( "tsize", p ) == 0 ) {
-                       p += 6;
-                       state->tsize = strtoul ( p, &p, 10 );
-                       if ( *p ) {
-                               DBG ( "TFTPCORE: garbage \"%s\" "
-                                     "after tsize\n", p );
-                               return 0;
-                       }
-                       p++;
-                       DBG ( "TFTPCORE: got tsize %d\n", state->tsize );
-               } else if ( strcasecmp ( "multicast", p ) == 0 ) {
-                       p += 10;
-                       char *e = strchr ( p, ',' );
-                       if ( ( ! e ) || ( e >= end ) ) {
-                               DBG ( "TFTPCORE: malformed multicast field "
-                                     "\"%s\"\n", p );
-                               return 0;
-                       }
-                       /* IP address may be missing, in which case we
-                        * should leave state->multicast.sin_addr
-                        * unaltered.
-                        */
-                       if ( e != p ) {
-                               int rc;
-                               *e = '\0';
-                               rc = inet_aton ( p,
-                                                &state->multicast.sin_addr );
-                               *e = ',';
-                               if ( ! rc ) {
-                                       DBG ( "TFTPCORE: malformed multicast "
-                                             "IP address \"%s\"\n", p );
-                                       return 0;
-                               }
-                       }
-                       p = e + 1;
-                       /* UDP port may also be missing */
-                       if ( *p != ',' ) {
-                               state->multicast.sin_port
-                                       = strtoul ( p, &p, 10 );
-                               if ( *p != ',' ) {
-                                       DBG ( "TFTPCORE: garbage \"%s\" "
-                                             "after multicast port\n", p );
-                                       return 0;
-                               }
-                       }
-                       p++;
-                       /* "Master Client" must always be present */
-                       state->master = strtoul ( p, &p, 10 );
-                       if ( *p ) {
-                               DBG ( "TFTPCORE: garbage \"%s\" "
-                                     "after multicast mc\n", p );
-                               return 0;
-                       }
-                       p++;
-                       DBG ( "TFTPCORE: got multicast %@:%d (%s)\n",
-                             state->multicast.sin_addr.s_addr,
-                             state->multicast.sin_port,
-                             ( state->master ? "master" : "not master" ) );
-               } else {
-                       DBG ( "TFTPCORE: unknown option \"%s\"\n", p );
-                       p += strlen ( p ) + 1; /* skip option name */
-                       p += strlen ( p ) + 1; /* skip option value */
-               }
-       }
-
-       if ( p > end ) {
-               DBG ( "TFTPCORE: overran options in OACK\n" );
-               return 0;
-       }
-
-       return 1;
-}
-
-/**
- * Acknowledge a TFTP packet
- *
- * @v state                            TFTP transfer state
- * @v tftp_state::server::sin_addr     TFTP server IP address
- * @v tftp_state::server::sin_port     TFTP server UDP port
- * @v tftp_state::lport                        Client UDP port
- * @v tftp_state::block                        Most recently received block number
- * @ret True                           Acknowledgement packet was sent
- * @ret False                          Acknowledgement packet was not sent
- * @err other                          As returned by udp_transmit()
- * 
- * Send a TFTP ACK packet for the most recently received block.
- *
- * This sends only a single ACK packet; it does not wait for the
- * server's response.
- */
-int tftp_ack_nowait ( struct tftp_state *state ) {
-       struct tftp_ack ack;
-
-       DBG ( "TFTPCORE: acknowledging data block %d\n", state->block );
-       ack.opcode = htons ( TFTP_ACK );
-       ack.block = htons ( state->block );
-       return udp_transmit ( state->server.sin_addr.s_addr,
-                             state->lport, state->server.sin_port,
-                             sizeof ( ack ), &ack );
-}
-
-/**
- * Acknowledge a TFTP packet and wait for a response
- *
- * @v state                            TFTP transfer state
- * @v tftp_state::server::sin_addr     TFTP server IP address
- * @v tftp_state::server::sin_port     TFTP server UDP port
- * @v tftp_state::lport                        Client UDP port
- * @v tftp_state::block                        Most recently received block number
- * @ret True                           Received a non-error response
- * @ret False                          Received error response / no response
- * @ret *reply                         The server's response, if any
- * @err #PXENV_STATUS_TFTP_READ_TIMEOUT        Timed out waiting for a response
- * @err other                          As returned by tftp_ack_nowait()
- * @err other                          As set by tftp_set_errno()
- *
- * Send a TFTP ACK packet for the most recently received data block,
- * and keep transmitting this ACK until we get a response from the
- * server (e.g. a new data block).
- *
- * If the response is a TFTP DATA packet, no processing is done.
- * Specifically, the block number is not checked to ensure that this
- * is indeed the next data block in the sequence, nor is
- * tftp_state::block updated with the new block number.
- *
- * If the response from the server is a TFTP ERROR packet, tftp_open()
- * will return False and #errno will be set accordingly.
- */
-int tftp_ack ( struct tftp_state *state, union tftp_any **reply ) {
-       int retry;
-
-       *reply = NULL;
-       for ( retry = 0 ; retry < MAX_TFTP_RETRIES ; retry++ ) {
-               long timeout = rfc2131_sleep_interval ( TFTP_REXMT, retry );
-               /* ACK the last data block */
-               if ( ! tftp_ack_nowait ( state ) ) {
-                       DBG ( "TFTP: could not send ACK: %m\n" );
-                       return 0;
-               }
-               if ( tftp_get ( state, timeout, reply ) ) {
-                       /* We got a non-error response */
-                       return 1;
-               }
-               if ( *reply ) {
-                       /* We got an error response */
-                       return 0;
-               }
-       }
-       DBG ( "TFTP: timed out during read\n" );
-       errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
-       return 0;
-}
-
-/**
- * Send a TFTP error
- *
- * @v state                            TFTP transfer state
- * @v tftp_state::server::sin_addr     TFTP server IP address
- * @v tftp_state::server::sin_port     TFTP server UDP port
- * @v tftp_state::lport                        Client UDP port
- * @v errcode                          TFTP error code
- * @v errmsg                           Descriptive error string, or NULL
- * @ret True                           Error packet was sent
- * @ret False                          Error packet was not sent
- *
- * Send a TFTP ERROR packet back to the server to terminate the
- * transfer.
- *
- * If #errmsg is NULL, the current error message string as returned by
- * strerror(errno) will be used as the error text.
- */
-int tftp_error ( struct tftp_state *state, int errcode, const char *errmsg ) {
-       struct tftp_error error;
-
-       DBG ( "TFTPCORE: aborting with error %d (%s)\n", errcode, errmsg );
-       error.opcode = htons ( TFTP_ERROR );
-       error.errcode = htons ( errcode );
-       strncpy ( error.errmsg, errmsg ? errmsg : strerror ( errno ),
-                 sizeof ( error.errmsg ) );
-       return udp_transmit ( state->server.sin_addr.s_addr,
-                             state->lport, state->server.sin_port,
-                             sizeof ( error ), &error );
-}
-
-/**
- * Interpret a TFTP error
- *
- * @v error                            Pointer to a struct tftp_error
- *
- * Sets #errno based on the error code in a TFTP ERROR packet.
- */
-void tftp_set_errno ( struct tftp_error *error ) {
-       static int errmap[] = {
-               [TFTP_ERR_FILE_NOT_FOUND] = PXENV_STATUS_TFTP_FILE_NOT_FOUND,
-               [TFTP_ERR_ACCESS_DENIED] = PXENV_STATUS_TFTP_ACCESS_VIOLATION,
-               [TFTP_ERR_ILLEGAL_OP] = PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
-       };
-       unsigned int errcode = ntohs ( error->errcode );
-       
-       errno = 0;
-       if ( errcode < ( sizeof(errmap) / sizeof(errmap[0]) ) )
-               errno = errmap[errcode];
-       if ( ! errno )
-               errno = PXENV_STATUS_TFTP_ERROR_OPCODE;
-}