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