1/**
2 * \file
3 * \brief TFTP library
4 */
5
6/*
7 * Copyright (c) 2015 ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#ifndef TFTP_INTERNAL_H_
16#define TFTP_INTERNAL_H_ 1
17
18/*
19 * ------------------------------------------------------------------------------
20 * General defines
21 * ------------------------------------------------------------------------------
22 */
23#define TFTP_BLOCKSIZE      512
24#define TFTP_MAX_MSGSIZE    (4 + TFTP_BLOCKSIZE)
25#define TFTP_TIMEOUT        500
26
27
28/*
29 * ------------------------------------------------------------------------------
30 * Debugging options
31 * ------------------------------------------------------------------------------
32 */
33//#define TFTP_DEBUG(x...) debug_printf("[tftp] " x)
34#define TFTP_DEBUG(x...)
35//#define TFTP_DEBUG_PACKETS(x...) debug_printf("[tftp] " x)
36#define TFTP_DEBUG_PACKETS(x...)
37
38/*
39 * ------------------------------------------------------------------------------
40 * operation codes
41 * ------------------------------------------------------------------------------
42 */
43
44///< TFTP Operation Codes
45typedef enum tftp_op {
46    TFTP_OP_INVALID   = 0,  ///< op code is invalid
47    TFTP_OP_READ_REQ  = 1,  ///< read request
48    TFTP_OP_WRITE_REQ = 2,  ///< write request
49    TFTP_OP_DATA      = 3,  ///< data response
50    TFTP_OP_ACK       = 4,  ///< ack response
51    TFTP_OP_ERROR     = 5   ///< error response
52} tpft_op_t;
53
54
55/**
56 * \brief writes the opcode into the buffer
57 *
58 * \param buf       buffer where to write the opcode to
59 * \param opcode    opcode to be written
60 *
61 * \return number of bytes written
62 */
63static inline size_t set_opcode(void *buf, uint16_t opcode)
64{
65    uint8_t *p = buf;
66    *p = ((opcode >> 8) & 0xff); p++;
67    *p = (opcode & 0xff);
68
69    return sizeof(uint16_t);
70}
71
72/**
73 * \brief obtains the opcode from the buffer
74 *
75 * \param buf   buffer where to extract the op code
76 *
77 * \return tftp op code
78 */
79static inline tpft_op_t get_opcode(void *buf)
80{
81    uint8_t *p = buf;
82    uint16_t opcode = (*p) << 8; p++;
83    opcode |= *p;
84
85    return (tpft_op_t)opcode;
86}
87
88/*
89 * ------------------------------------------------------------------------------
90 * Operation codes
91 * ------------------------------------------------------------------------------
92 */
93
94///< TFTP state
95typedef enum tpft_st {
96    TFTP_ST_INVALID,        ///< state is invalid
97    TFTP_ST_CLOSED,         ///< connection is closed
98    TFTP_ST_IDLE,           ///< the client is connected and in the  idle state
99    TFTP_ST_LAST_ACK_SENT,  ///< last ack has been sent
100    TFTP_ST_LAST_DATA_SENT, ///< last data response sent
101    TFTP_ST_ERROR,          ///< tftp request resulted in an error
102    TFTP_ST_READ_REQ_SENT,  ///< a read request has been sent
103    TFTP_ST_WRITE_REQ_SENT, ///< a write request has been sent
104    TFTP_ST_DATA_SENT,      ///< data respnse is being sent
105    TFTP_ST_ACK_SENT,       ///< ack has been sent
106} tftp_st_t;
107
108
109/*
110 * ------------------------------------------------------------------------------
111 * Transfer modes
112 * ------------------------------------------------------------------------------
113 */
114
115///< operation mode of the TFTP connection
116typedef enum tftp_mode {
117    TFTP_MODE_INVALID,      ///< invalid operation mode
118    TFTP_MODE_OCTET,        ///< use octet moded
119    TFTP_MODE_NETASCII,     ///< use netsascii mode
120    TFTP_MODE_MAIL,         ///< use mail mode
121} tftp_mode_t;
122
123/**
124 * \brief sets the transfer mode in a buffer
125 *
126 * \param buf   buffer where to write the transfer mode to
127 * \param mode  transfer mode to write
128 *
129 * \returns number of bytes written
130 */
131static inline size_t set_mode(void *buf, tftp_mode_t mode)
132{
133    switch(mode) {
134        case TFTP_MODE_OCTET:
135            return snprintf(buf, 6, "octet")+1;
136            break;
137        case TFTP_MODE_NETASCII:
138            return snprintf(buf, 6, "netascii")+1;
139            break;
140        case TFTP_MODE_MAIL:
141            return snprintf(buf, 5, "mail")+1;
142            break;
143        default:
144            assert(!"this should not happen");
145            return 0;
146    }
147}
148
149/**
150 * \brief parses the transfer mode from the buffer
151 *
152 * \param buf   buffer to extract the transfer mode from
153 *
154 * \return tftp transfer mode
155 */
156static inline tftp_mode_t get_mode(void *buf)
157{
158    if (strncmp(buf, "octet", 5) == 0) {
159        return TFTP_MODE_OCTET;
160    } else if (strncmp(buf, "netascii", 8) == 0) {
161        return TFTP_MODE_NETASCII;
162    } else if (strncmp(buf, "mail", 4) == 0) {
163        return TFTP_MODE_MAIL;
164    }
165
166    return TFTP_MODE_INVALID;
167}
168
169/*
170 * ------------------------------------------------------------------------------
171 * Error
172 * ------------------------------------------------------------------------------
173 */
174
175///< possible tftp errors in packages
176typedef enum tftp_err {
177    TFTP_ERR_NOT_DEFINED = 0,             ///< not defined
178    TFTP_ERR_NOT_FOUND =  1,              ///< file not found
179    TFTP_ERR_ACCESS_DENIED =  2,          ///< access denied
180    TFTP_ERR_DISK_FULL = 3,               ///< disk is full
181    TFTP_ERR_UNKNOWN_TID =   4,           ///< unkown transfer id
182    TFTP_ERR_ILLEGAL_OP = 5,              ///< illegal operation
183    TFTP_ERR_FILE_EXISTS =  6,            ///< destination file exist
184    TFTP_ERR_NO_SUCH_USER =  7,           ///< no such user
185    TFTP_ERR_INVALID_BUFFER = 0xFFFFFFFF, ///< invalid buffer
186} tftp_err_t;
187
188/**
189 * \brief extracts the error code from an error package
190 *
191 * \param buf       buffer to extract the error code from
192 * \param buflen    length of the buffer in bytes
193 *
194 * \returns tftp error code
195 */
196static inline tftp_err_t get_error(void *buf, size_t buflen) {
197    if (buflen < 5) {
198        return TFTP_ERR_INVALID_BUFFER;
199    }
200    uint8_t *p = buf;
201
202    return (tftp_err_t)((p[2] << 8) + p[3]);
203}
204
205/**
206 * \brief sets the error code in a buffer
207 *
208 * \param buf   buffer where to write the error code
209 * \param error error code to write
210 *
211 * \returns number of bytes written
212 */
213static inline size_t set_error(void *buf, tftp_err_t error)
214{
215    uint8_t *p = buf;
216    p[0] = 0;
217    p[1] = 1;
218    p[2] = ((error >> 8) & 0xff);
219    p[3] = (error & 0xff);
220
221    return 4;
222}
223
224/*
225 * ------------------------------------------------------------------------------
226 * Data packets
227 * ------------------------------------------------------------------------------
228 */
229
230/**
231 * \brief extracts the block number from a buffer
232 *
233 * \param buf       buffer where to extract the block number
234 * \param buflen    length of the buffer
235 *
236 * \return block number or TFTP_BLOCKNO_INVALID
237 */
238static inline uint32_t get_block_no(void *buf, size_t buflen)
239{
240    if (buflen < 4) {
241        return TFTP_ERR_INVALID_BUFFER;
242    }
243
244    uint8_t *data = buf;
245    return (data[2] << 8) + data[3];
246}
247
248/**
249 * \brief sets the block number in a buffer
250 *
251 * \param buf       buffer where to write the block number to
252 * \param blockno   block number to write
253 *
254 * \return  number of bytes written
255 */
256static inline size_t set_block_no(void *buf, uint16_t blockno) {
257    uint8_t *p = buf;
258    *p = (uint8_t)((blockno >> 8) & 0xff); p++;
259    *p = (uint8_t)(blockno & 0xff);
260    return sizeof(uint16_t);
261}
262
263/*
264 * ------------------------------------------------------------------------------
265 * Sending generic messages
266 * ------------------------------------------------------------------------------
267 */
268errval_t tftp_send_ack(struct net_socket *socket, uint32_t blockno,
269                       struct in_addr addr, uint16_t port);
270#endif /* TFTP_INTERNAL_H_ */
271