1 // Copyright 2017 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 #include <stdbool.h> 8 #include <stdint.h> 9 #include <stdlib.h> 10 #include <sys/types.h> 11 12 /** 13 * This is a library that implements TFTP (RFC 1350) with support for the 14 * option extension (RFC 2347) the block size (RFC 2348) timeout interval, 15 * transfer size (RFC 2349) and the window size (RFC 7440) options. 16 * 17 * It also supports block count rollover, which allows us to transfer files 18 * larger than 65536 * block size bytes. This is purported to be a common 19 * extension of the TFTP protocol. 20 * 21 * This library does not deal with the transport of the protocol itself and 22 * should be able to be plugged into an existing client or server program. 23 * 24 * Memory management is the responsibility of the client of the library, 25 * allowing its use in more restricted environments like bootloaders. 26 * 27 * To use this library, one should initialize a TFTP Session and generate 28 * a request if the transfer needs to be triggered by the consumer of this 29 * library. 30 * 31 * Once a transfer has been successfully started, repeated calls to the receive 32 * method should be made with the incoming data. Outgoing packets will be 33 * generated in the outgoing buffer parameters to each method call. 34 * 35 * In the case of the passive side of the connection, the receive method should 36 * be called repeatedly as well. Upon reception of the first packet the 37 * |tftp_file_open_cb| callback will be called to prepare for receiving the 38 * file. 39 * 40 * A timeout value is returned when calling |tftp_generate_request| and 41 * |tftp_process_msg| and should be used to notify the library that the 42 * expected packet was not receive within the value returned. 43 **/ 44 45 enum { 46 TFTP_NO_ERROR = 0, 47 TFTP_TRANSFER_COMPLETED = 1, 48 49 TFTP_ERR_INTERNAL = -1, 50 TFTP_ERR_NOT_SUPPORTED = -2, 51 TFTP_ERR_NOT_FOUND = -3, 52 TFTP_ERR_INVALID_ARGS = -10, 53 TFTP_ERR_BUFFER_TOO_SMALL = -15, 54 TFTP_ERR_BAD_STATE = -20, 55 TFTP_ERR_TIMED_OUT = -21, 56 TFTP_ERR_SHOULD_WAIT = -22, 57 TFTP_ERR_IO = -40, 58 }; 59 60 enum { 61 TFTP_ERR_CODE_UNDEF = 0, 62 TFTP_ERR_CODE_FILE_NOT_FOUND = 1, 63 TFTP_ERR_CODE_ACCESS_VIOLATION = 2, 64 TFTP_ERR_CODE_DISK_FULL = 3, 65 TFTP_ERR_CODE_ILLEGAL_OP = 4, 66 TFTP_ERR_CODE_UNKNOWN_ID = 5, 67 TFTP_ERR_CODE_FILE_EXISTS = 6, 68 TFTP_ERR_CODE_NO_USER = 7, 69 TFTP_ERR_CODE_BAD_OPTIONS = 8, 70 71 // Fuchsia-specific error code 72 // BUSY is sent by a server as a response to a RRQ or WRQ, and indicates 73 // that the server is unavailable to process the request at the moment 74 // (but expects to be able to handle it at some time in the future). 75 // A server will send an ERR_CODE_BUSY response if its open callback 76 // (open_read or open_write) returns TFTP_ERR_SHOULD_WAIT. 77 TFTP_ERR_CODE_BUSY = 0x143, /* 'B' + 'U' + 'S' + 'Y' */ 78 }; 79 80 #ifdef __cplusplus 81 extern "C" { 82 #endif 83 84 // Opaque structure 85 typedef struct tftp_session_t tftp_session; 86 87 typedef int32_t tftp_status; 88 89 typedef enum { 90 MODE_NETASCII, 91 MODE_OCTET, 92 MODE_MAIL, 93 } tftp_mode; 94 95 // These are the default values used when sending a tftp request 96 #define TFTP_DEFAULT_CLIENT_MODE MODE_OCTET 97 98 typedef struct { 99 char* inbuf; // required - buffer for assembling incoming msgs 100 size_t inbuf_sz; // required 101 char* outbuf; // required - buffer for assembling outgoing msgs 102 size_t outbuf_sz; // required 103 tftp_mode* mode; 104 uint16_t* block_size; 105 uint16_t* window_size; 106 uint8_t* timeout; 107 char* err_msg; 108 size_t err_msg_sz; 109 } tftp_request_opts; 110 111 typedef struct { 112 char* inbuf; // required - buffer for assembling incoming msgs 113 size_t inbuf_sz; // required 114 char* outbuf; // required - buffer for assembling outgoing msgs 115 size_t* outbuf_sz; // required 116 char* err_msg; 117 size_t err_msg_sz; 118 } tftp_handler_opts; 119 120 // tftp_file_open_read_cb is called by the library to prepare for reading. 121 // |file_cookie| will be passed to this function from the argument to 122 // tftp_process_msg. 123 // 124 // This function should return the size of the file on success, or a TFTP_ERR_* 125 // error code on failure. 126 typedef ssize_t (*tftp_file_open_read_cb)(const char* filename, 127 void* file_cookie); 128 129 // tftp_file_open_write_cb is called by the library to prepare a file for 130 // writing. |file_cookie| will be passed to this function from the argument to 131 // tftp_process_msg. |size| indicates the size of the file that will be 132 // created (it may be ignored if this information is not needed on opening). 133 typedef tftp_status (*tftp_file_open_write_cb)(const char* filename, 134 size_t size, 135 void* file_cookie); 136 137 // tftp_file_read_cb is called by the library to read |length| bytes, starting 138 // at |offset|, into |data|. |file_cookie| will be passed to this function from 139 // the argument to tftp_process_msg. 140 // 141 // |length| is both an input and output parameter, and may be set as a value 142 // less than or equal to the original value to indicate a partial read. 143 // |length| is only used as an output parameter if the returned status is 144 // TFTP_NO_ERROR. 145 typedef tftp_status (*tftp_file_read_cb)(void* data, 146 size_t* length, 147 off_t offset, 148 void* file_cookie); 149 150 // tftp_file_write_cb is called by the library to write |length| bytes, 151 // starting at |offset|, into the destination. |file_cookie| will be passed to 152 // this function from the argument to tftp_process_msg. 153 // 154 // |length| is both an input and output parameter, and may be set as a value 155 // less than or equal to the original value to indicate a partial write. 156 // |length| is only used as an output parameter if the returned status is 157 // TFTP_NO_ERROR. 158 typedef tftp_status (*tftp_file_write_cb)(const void* data, 159 size_t* length, 160 off_t offset, 161 void* file_cookie); 162 163 // tftp_file_close_cb is called by the library to finish a file read or write 164 // operation. |file_cookie| will be passed to this function from the argument to 165 // tftp_process_msg. 166 typedef void (*tftp_file_close_cb)(void* file_cookie); 167 168 typedef struct { 169 tftp_file_open_read_cb open_read; 170 tftp_file_open_write_cb open_write; 171 tftp_file_read_cb read; 172 tftp_file_write_cb write; 173 tftp_file_close_cb close; 174 } tftp_file_interface; 175 176 // tftp_transport_send_cb is called by the library to send |len| bytes from 177 // |data| over a previously-established connection. 178 typedef tftp_status (*tftp_transport_send_cb)(void* data, 179 size_t len, 180 void* transport_cookie); 181 182 // tftp_transport_recv_cb is called by the library to read from the transport 183 // interface. It will read values into |data|, up to |len| bytes. If |block| is 184 // set, the operation will block until data is received or a timeout happens. 185 // (For starting communication, the timeout should be set by the user if 186 // desired. Once communication has been established, the timeout is set by the 187 // tftp library using the timeout_set callback). 188 // On success, the function should return the number of bytes received. On 189 // failure it should return a tftp_status error code. 190 typedef int (*tftp_transport_recv_cb)(void* data, 191 size_t len, 192 bool block, 193 void* transport_cookie); 194 195 // tftp_transport_timeout_set_cb is called by the library to set the timeout 196 // length of the transport interface. This function should return 0 on success 197 // or -1 on failure. 198 typedef int (*tftp_transport_timeout_set_cb)(uint32_t timeout_ms, 199 void* transport_cookie); 200 201 typedef struct { 202 tftp_transport_send_cb send; 203 tftp_transport_recv_cb recv; 204 tftp_transport_timeout_set_cb timeout_set; 205 } tftp_transport_interface; 206 207 // Returns the number of bytes needed to hold a tftp_session. 208 size_t tftp_sizeof_session(void); 209 210 // Initialize the tftp_session pointer using the memory in |buffer| of size 211 // |size|. Returns TFTP_ERR_BUFFER_TOO_SMALL if |size| is too small. 212 tftp_status tftp_init(tftp_session** session, void* buffer, size_t size); 213 214 // Specifies the callback functions to use when reading or writing files. 215 tftp_status tftp_session_set_file_interface(tftp_session* session, 216 tftp_file_interface* callbacks); 217 218 // Specifies the callback functions to use for the network interface. Note that 219 // setting up the transport must be performed outside of the purview of the 220 // library, since the initial configuration options are highly interface- 221 // dependent. 222 tftp_status tftp_session_set_transport_interface(tftp_session* session, 223 tftp_transport_interface* callbacks); 224 225 // Specifies how many consecutive timeouts we will endure before terminating 226 // a session. 227 void tftp_session_set_max_timeouts(tftp_session* session, 228 uint16_t max_timeouts); 229 230 // Specify whether to use the upper 8 bits of the opcode field as a pseudo 231 // retransmission count. When enabled, this tweaks the contents of a 232 // retransmitted packet just enough that it will have a different checksum, 233 // avoiding the problem we have on ASIX 88179 adapters that (reliably) 234 // generate incorrect checksums for certain packets. 235 void tftp_session_set_opcode_prefix_use(tftp_session* session, 236 bool enable); 237 238 // When acting as a server, the options that will be overridden when a 239 // value is requested by the client. Note that if the client does not 240 // specify a setting, the default will be used regardless of server 241 // setting. 242 // When acting as a client, the default options that will be used when 243 // initiating a transfer. If any of the values are not set, it will not be 244 // specified in the request packet, and so the tftp defaults will be used. 245 tftp_status tftp_set_options(tftp_session* session, 246 const uint16_t* block_size, 247 const uint8_t* timeout, 248 const uint16_t* window_size); 249 250 // tftp_session_has_pending returns true if the tftp_session has more data to 251 // send before waiting for an ack. It is recommended that the caller do a 252 // non-blocking read to see if an out-of-order ACK was sent by the remote host 253 // before sending additional data packets. 254 bool tftp_session_has_pending(tftp_session* session); 255 256 // Prepare a DATA packet to send to the remote host. This is only required when 257 // tftp_session_has_pending(session) returns true, as tftp_process_msg() will 258 // prepare the first DATA message in each window. 259 tftp_status tftp_prepare_data(tftp_session* session, 260 void* outgoing, 261 size_t* outlen, 262 uint32_t* timeout_ms, 263 void* cookie); 264 265 // If no response from the peer is received before the most recent timeout_ms 266 // value, this function should be called to take the next appropriate action 267 // (e.g., retransmit or cancel). |msg_buf| must point to the last message sent, 268 // which is |msg_len| bytes long. |buf_sz| represents the total size of 269 // |msg_buf|, which may be used to assemble the next packet to send. 270 // |timeout_ms| is set to the next timeout value the user of the library should 271 // use when waiting for a response. |file_cookie| will be passed to the tftp 272 // callback functions. On return, TFTP_ERR_TIMED out is returned if the maximum 273 // number of timeouts has been exceeded. If a message should be sent out, 274 // |msg_len| will be set to the size of the message. 275 tftp_status tftp_timeout(tftp_session* session, 276 void* msg_buf, 277 size_t* msg_len, 278 size_t buf_sz, 279 uint32_t* timeout_ms, 280 void* file_cookie); 281 282 // Request to send the file |local_filename| across an existing session to 283 // |remote_filename| on the target. |options| are required for the input and 284 // output buffers, but other options can be left as NULL to use the session 285 // defaults. Before calling this function, the client transport interface 286 // should be configured as needed. 287 tftp_status tftp_push_file(tftp_session* session, 288 void* transport_cookie, 289 void* file_cookie, 290 const char* local_filename, 291 const char* remote_filename, 292 tftp_request_opts* options); 293 294 // Request to retrieve the target file |remote_filename| across an existing 295 // session to |local_filename| on the host. |options| are required for the 296 // input and output buffers, but other options can be left as NULL to use the 297 // session defaults. Before calling this function, the client transport 298 // interface should be configured as needed. 299 tftp_status tftp_pull_file(tftp_session* session, 300 void* transport_cookie, 301 void* file_cookie, 302 const char* remote_filename, 303 const char* local_filename, 304 tftp_request_opts* options); 305 306 // Wait for a client to request an operation, then service that request. 307 // Returns (with TFTP_TRANSFER_COMPLETED) after each successful operation, or 308 // on error. This function will call the transport send, recv, and timeout_set 309 // operations as needed to facilitate communication with the requestor. 310 tftp_status tftp_service_request(tftp_session* session, 311 void* transport_cookie, 312 void* file_cookie, 313 tftp_handler_opts* opts); 314 315 // Processes a single message from the requestor, which is passed in as the 316 // inbuf component of |opts|. Responds to the request and updates the 317 // connection timeout using the appropriate transport send and timeout_set 318 // functions. Also, sets the value of outbuf_sz in |opts| to the size of 319 // the message sent (or 0 if no message was sent). 320 tftp_status tftp_handle_msg(tftp_session* session, 321 void* transport_cookie, 322 void* file_cookie, 323 tftp_handler_opts* opts); 324 325 // TODO: tftp_error() for client errors that need to be sent to the remote host 326 327 #ifdef __cplusplus 328 } // extern "C" 329 #endif 330