summaryrefslogtreecommitdiffstats
path: root/src/proto
diff options
context:
space:
mode:
authorMichael Brown2005-05-31 17:21:33 +0200
committerMichael Brown2005-05-31 17:21:33 +0200
commit7d63b39e3d8c633b2f94b68562fd6f2cdfb2ade7 (patch)
tree99282e8f636bedb91a66cb6181f9dff47ad72133 /src/proto
parentFirst version (diff)
downloadipxe-7d63b39e3d8c633b2f94b68562fd6f2cdfb2ade7.tar.gz
ipxe-7d63b39e3d8c633b2f94b68562fd6f2cdfb2ade7.tar.xz
ipxe-7d63b39e3d8c633b2f94b68562fd6f2cdfb2ade7.zip
Add tftp_ack() and tftp_error()
Diffstat (limited to 'src/proto')
-rw-r--r--src/proto/tftpcore.c80
1 files changed, 73 insertions, 7 deletions
diff --git a/src/proto/tftpcore.c b/src/proto/tftpcore.c
index da4399e5..0bdffef7 100644
--- a/src/proto/tftpcore.c
+++ b/src/proto/tftpcore.c
@@ -25,10 +25,20 @@
* (i.e. comes from the TFTP server, has the correct destination port,
* and is addressed either to our IP address or to our multicast
* listening address).
+ *
+ * Invoke await_tftp() using 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 ) {
+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 */
@@ -55,13 +65,13 @@ static int await_tftp ( int ival __unused, void *ptr,
/**
* Issue a TFTP open request (RRQ)
*
- * @v filename File name
* @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::client::sin_addr Client multicast IP address, or 0.0.0.0
* @v tftp_state::client::sin_port Client UDP port, or 0
* @v tftp_state::blksize Requested blksize, or 0
+ * @v filename File name
* @ret True Received a non-error response
* @ret False Received error response / no response
* @ret tftp_state::client::sin_port Client UDP port
@@ -120,7 +130,7 @@ static int await_tftp ( int ival __unused, void *ptr,
* leave_group() at appropriate times.
*
*/
-int tftp_open ( const char *filename, struct tftp_state *state,
+int tftp_open ( struct tftp_state *state, const char *filename,
union tftp_any **tftp ) {
static unsigned short lport = 2000; /* local port */
int fixed_lport;
@@ -165,6 +175,9 @@ int tftp_open ( const char *filename, struct tftp_state *state,
state->client.sin_port = ++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->client.sin_port );
if ( ! udp_transmit ( state->server.sin_addr.s_addr,
state->client.sin_port,
state->server.sin_port,
@@ -185,8 +198,8 @@ int tftp_open ( const char *filename, struct tftp_state *state,
/**
* Process a TFTP OACK packet
*
- * @v oack The 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
@@ -213,7 +226,7 @@ int tftp_open ( const char *filename, struct tftp_state *state,
* #TFTP_DEFAULT_BLKSIZE before returning, you probably don't need to
* worry about this.
*/
-int tftp_process_opts ( struct tftp_oack *oack, struct tftp_state *state ) {
+int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
const char *p;
const char *end;
@@ -297,3 +310,56 @@ int tftp_process_opts ( struct tftp_oack *oack, struct tftp_state *state ) {
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::client::sin_port 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
+ *
+ * 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 ( struct tftp_state *state ) {
+ struct tftp_ack ack;
+
+ ack.opcode = htons ( TFTP_ACK );
+ ack.block = htons ( state->block );
+ return udp_transmit ( state->server.sin_addr.s_addr,
+ state->client.sin_port, state->server.sin_port,
+ sizeof ( ack ), &ack );
+}
+
+/**
+ * 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::client::sin_port Client UDP port
+ * @v err TFTP error code
+ * @v errmsg Descriptive error string
+ * @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.
+ */
+int tftp_error ( struct tftp_state *state, int err, const char *errmsg ) {
+ struct tftp_error error;
+
+ DBG ( "TFTPCORE: aborting with error %d (%s)\n", err, errmsg );
+ error.opcode = htons ( TFTP_ERROR );
+ error.errcode = htons ( err );
+ strncpy ( error.errmsg, errmsg, sizeof ( error.errmsg ) );
+ return udp_transmit ( state->server.sin_addr.s_addr,
+ state->client.sin_port, state->server.sin_port,
+ sizeof ( error ), &error );
+}