+
+/**
+ * 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 );
+}