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