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 <stddef.h>
8#include <stdint.h>
9
10#include "tftp/tftp.h"
11
12#define OPCODE_RRQ 1
13#define OPCODE_WRQ 2
14#define OPCODE_DATA 3
15#define OPCODE_ACK 4
16#define OPCODE_ERROR 5
17#define OPCODE_OACK 6
18
19#ifdef __cplusplus
20extern "C" {
21#endif
22
23typedef struct tftp_msg_t {
24    uint16_t opcode;
25    char data[0];
26} tftp_msg;
27
28typedef struct tftp_err_msg_t {
29    uint16_t opcode;
30    uint16_t err_code;
31    char msg[0];
32} tftp_err_msg;
33
34typedef struct tftp_data_msg_t {
35    uint16_t opcode;
36    uint16_t block;
37    uint8_t data[0];
38} tftp_data_msg;
39
40#define BLOCKSIZE_OPTION 0x01  // RFC 2348
41#define TIMEOUT_OPTION 0x02    // RFC 2349
42#define WINDOWSIZE_OPTION 0x04 // RFC 7440
43
44#define DEFAULT_BLOCKSIZE 512
45#define DEFAULT_TIMEOUT 1
46#define DEFAULT_FILESIZE 0
47#define DEFAULT_WINDOWSIZE 1
48#define DEFAULT_MODE MODE_OCTET
49#define DEFAULT_MAX_TIMEOUTS 5
50#define DEFAULT_USE_OPCODE_PREFIX true
51
52typedef struct tftp_options_t {
53    // A bitmask of the options that have been set
54    uint8_t mask;
55
56    uint16_t block_size;
57    uint8_t timeout;
58    uint16_t window_size;
59} tftp_options;
60
61/**
62  State transitions
63
64  ***** READ FILE *****
65
66    client                                                  server
67    ~~~~~~                                                  ~~~~~~
68    NONE                                                      NONE
69        generate_request (rrq)
70    REQ_SENT
71                                ---- RRQ ----->
72                                                 handle_rrq
73                                                      REQ_RECEIVED
74                               <---- OACK ----
75                  handle_oack
76    FIRST_DATA
77
78+------+                                                      +-----+
79|      |                                                      |     |
80|      V                                                      V     |
81|                               ---- ACK ----->                     |
82|                                                handle_ack         |
83|                                                     SENDING_DATA  |
84|                              <---- DATA ----                |     |
85|                 handle_data                                 |     |
86|   RECEIVING_DATA                                            |     |
87|                                    ...                      |     |
88|                              <---- DATA ----                |     |
89|                 handle_data                                 |     |
90|      |                                                      |     |
91+------+                                                      +-----+
92
93         COMPLETED                                    COMPLETED
94
95
96    ****** WRITE FILE *****
97
98    client                                                  server
99    ~~~~~~                                                  ~~~~~~
100    NONE                                                      NONE
101        generate_request (wrq)
102    REQ_SENT
103                                ---- WRQ ----->
104                                                 handle_wrq
105                                                      REQ_RECEIVED
106                               <---- OACK ----
107                  handle_oack
108    FIRST_DATA
109
110+------+                                                        +-----+
111|      |                                                        |     |
112|      V                                                        V     |
113|                               ---- DATA ---->                       |
114|                                                handle_data          |
115|                                                     RECEIVING_DATA  |
116|                              <----- ACK ----                  |     |
117|                 handle_ack                                    |     |
118|   SENDING_DATA                                                |     |
119|      |                                                        |     |
120+------+                                                        +-----+
121
122         COMPLETED                                    COMPLETED
123
124**/
125
126typedef enum {
127    NONE = 0,
128    REQ_SENT,
129    REQ_RECEIVED,
130    FIRST_DATA,
131    SENDING_DATA,
132    RECEIVING_DATA,
133    ERROR,
134    COMPLETED,
135} tftp_state;
136
137typedef enum {
138    SEND_FILE,
139    RECV_FILE
140} tftp_file_direction;
141
142struct tftp_session_t {
143
144    // For a client, the options we will use on a new connection. For a server, the options we
145    // will override, if possible, when we receive a write request.
146    tftp_options options;
147
148    // Tracks the options we used on the last request, so we can compare them to the options
149    // we get back.
150    tftp_options client_sent_opts;
151
152    // Maximum filename really is 505 including \0
153    // max request size (512) - opcode (2) - shortest mode (4) - null (1)
154    char filename[512];
155    tftp_mode mode;
156
157    // General state values
158    tftp_file_direction direction;  // Not valid when state is NONE, ERROR, or COMPLETED.
159    tftp_state state;
160    size_t offset;
161    uint32_t consecutive_timeouts;
162    uint8_t opcode_prefix;
163    uint64_t block_number;
164    uint32_t window_index;
165
166    // Maximum number of times we will retransmit a single msg before aborting
167    uint16_t max_timeouts;
168
169    // Add an 8-bit prefix to the opcode so that retransmissions differ from the
170    // original transmission. This fixes problems with checksums on asix 88179 USB
171    // adapters (they send 0 checksums when they should send 0xffff, which is a
172    // no-no in IPv6). This modification is not RFC-compatible.
173    bool use_opcode_prefix;
174
175    // "Negotiated" values
176    size_t file_size;
177    uint16_t window_size;
178    uint16_t block_size;
179    uint8_t timeout;
180
181    // Callbacks
182    tftp_file_interface file_interface;
183    tftp_transport_interface transport_interface;
184};
185
186// Generates a read or write request to send to a tftp server. |filename| is
187// the name sent to the server. |datalen| is the size of the data (should be
188// zero for read requests). If |block_size|, |timeout|, or |window_size| are
189// set, those will be passed to the server in such a way that they cannot be
190// negotiated (normal, negotiable settings can be set using
191// tftp_set_options()). |outgoing| must point to a scratch buffer the library
192// can use to assemble the request. |outlen| is the size of the outgoing
193// scratch buffer, and will be set to the size of the request. |timeout_ms| is
194// set to the next timeout value the user of the library should use when
195// waiting for a response.
196tftp_status tftp_generate_request(tftp_session* session,
197                                  tftp_file_direction direction,
198                                  const char* local_filename,
199                                  const char* remote_filename,
200                                  tftp_mode mode,
201                                  size_t datalen,
202                                  const uint16_t* block_size,
203                                  const uint8_t* timeout,
204                                  const uint16_t* window_size,
205                                  void* outgoing,
206                                  size_t* outlen,
207                                  uint32_t* timeout_ms);
208
209// Handle an incoming tftp packet. |incoming| must point to the packet of size
210// |inlen|. |outgoing| must point to a scratch buffer the library can use to
211// assemble the next packet to send. |outlen| is the size of the outgoing
212// scratch buffer. |timeout_ms| is set to the next timeout value the user of the
213// library should use when waiting for a response. |cookie| will be passed to
214// the tftp callback functions.
215tftp_status tftp_process_msg(tftp_session* session,
216                             void* incoming,
217                             size_t inlen,
218                             void* outgoing,
219                             size_t* outlen,
220                             uint32_t* timeout_ms,
221                             void* cookie);
222
223// Internal handlers
224tftp_status tx_data(tftp_session* session, tftp_data_msg* resp, size_t* outlen, void* cookie);
225tftp_status tftp_handle_rrq(tftp_session* session,
226                            tftp_msg* rrq,
227                            size_t rrq_len,
228                            tftp_msg* resp,
229                            size_t* resp_len,
230                            uint32_t* timeout_ms,
231                            void* cookie);
232tftp_status tftp_handle_wrq(tftp_session* session,
233                            tftp_msg* wrq,
234                            size_t wrq_len,
235                            tftp_msg* resp,
236                            size_t* resp_len,
237                            uint32_t* timeout_ms,
238                            void* cookie);
239tftp_status tftp_handle_data(tftp_session* session,
240                             tftp_msg* msg,
241                             size_t msg_len,
242                             tftp_msg* resp,
243                             size_t* resp_len,
244                             uint32_t* timeout_ms,
245                             void* cookie);
246tftp_status tftp_handle_ack(tftp_session* session,
247                            tftp_msg* ack,
248                            size_t ack_len,
249                            tftp_msg* resp,
250                            size_t* resp_len,
251                            uint32_t* timeout_ms,
252                            void* cookie);
253tftp_status tftp_handle_error(tftp_session* session,
254                              tftp_err_msg* err,
255                              size_t err_len,
256                              tftp_msg* resp,
257                              size_t* resp_len,
258                              uint32_t* timeout_ms,
259                              void* cookie);
260tftp_status tftp_handle_oack(tftp_session* session,
261                             tftp_msg* oack,
262                             size_t oack_len,
263                             tftp_msg* resp,
264                             size_t* resp_len,
265                             uint32_t* timeout_ms,
266                             void* cookie);
267tftp_status tftp_handle_oerror(tftp_session* session,
268                               tftp_msg* oerr,
269                               size_t oerr_len,
270                               tftp_msg* resp,
271                               size_t* resp_len,
272                               uint32_t* timeout_ms,
273                               void* cookie);
274
275void print_hex(uint8_t* buf, size_t len);
276
277#ifdef __cplusplus
278}  // extern "C"
279#endif
280