1 /*
2 * Copyright (c) 2020 InnBlue
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(tftp_client, CONFIG_TFTP_LOG_LEVEL);
9
10 #include <stddef.h>
11 #include <zephyr/net/tftp.h>
12 #include "tftp_client.h"
13
14 #define ADDRLEN(sa) \
15 (sa.sa_family == AF_INET ? \
16 sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))
17
18 /*
19 * Prepare a request as required by RFC1350. This packet can be sent
20 * out directly to the TFTP server.
21 */
make_request(uint8_t * buf,int request,const char * remote_file,const char * mode)22 static size_t make_request(uint8_t *buf, int request,
23 const char *remote_file, const char *mode)
24 {
25 char *ptr = (char *)buf;
26 const char def_mode[] = "octet";
27
28 /* Fill in the Request Type. */
29 sys_put_be16(request, ptr);
30 ptr += 2;
31
32 /* Copy the name of the remote file. */
33 strncpy(ptr, remote_file, TFTP_MAX_FILENAME_SIZE);
34 ptr += strlen(remote_file);
35 *ptr++ = '\0';
36
37 /* Default to "Octet" if mode not specified. */
38 if (mode == NULL) {
39 mode = def_mode;
40 }
41
42 /* Copy the mode of operation. */
43 strncpy(ptr, mode, TFTP_MAX_MODE_SIZE);
44 ptr += strlen(mode);
45 *ptr++ = '\0';
46
47 return ptr - (char *)buf;
48 }
49
50 /*
51 * Send Data message to the TFTP Server and receive ACK message from it.
52 */
send_data(int sock,struct tftpc * client,uint32_t block_no,const uint8_t * data_buffer,size_t data_size)53 static int send_data(int sock, struct tftpc *client, uint32_t block_no, const uint8_t *data_buffer,
54 size_t data_size)
55 {
56 int ret;
57 int send_count = 0, ack_count = 0;
58 struct zsock_pollfd fds = {
59 .fd = sock,
60 .events = ZSOCK_POLLIN,
61 };
62
63 LOG_DBG("Client send data: block no %u, size %u", block_no, data_size + TFTP_HEADER_SIZE);
64
65 do {
66 if (send_count > TFTP_REQ_RETX) {
67 LOG_ERR("No more retransmits. Exiting");
68 return TFTPC_RETRIES_EXHAUSTED;
69 }
70
71 /* Prepare DATA packet, send it out then poll for ACK response */
72 sys_put_be16(DATA_OPCODE, client->tftp_buf);
73 sys_put_be16(block_no, client->tftp_buf + 2);
74 memcpy(client->tftp_buf + TFTP_HEADER_SIZE, data_buffer, data_size);
75
76 ret = zsock_send(sock, client->tftp_buf, data_size + TFTP_HEADER_SIZE, 0);
77 if (ret < 0) {
78 LOG_ERR("send() error: %d", -errno);
79 return -errno;
80 }
81
82 do {
83 if (ack_count > TFTP_REQ_RETX) {
84 LOG_WRN("No more waiting for ACK");
85 break;
86 }
87
88 ret = zsock_poll(&fds, 1, CONFIG_TFTPC_REQUEST_TIMEOUT);
89 if (ret < 0) {
90 LOG_ERR("recv() error: %d", -errno);
91 return -errno; /* IO error */
92 } else if (ret == 0) {
93 break; /* no response, re-send data */
94 }
95
96 ret = zsock_recv(sock, client->tftp_buf, TFTPC_MAX_BUF_SIZE, 0);
97 if (ret < 0) {
98 LOG_ERR("recv() error: %d", -errno);
99 return -errno;
100 }
101
102 if (ret != TFTP_HEADER_SIZE) {
103 break; /* wrong response, re-send data */
104 }
105
106 uint16_t opcode = sys_get_be16(client->tftp_buf);
107 uint16_t blockno = sys_get_be16(client->tftp_buf + 2);
108
109 LOG_DBG("Receive: opcode %u, block no %u, size %d",
110 opcode, blockno, ret);
111
112 if (opcode == ACK_OPCODE && blockno == block_no) {
113 return TFTPC_SUCCESS;
114 } else if (opcode == ACK_OPCODE && blockno < block_no) {
115 LOG_WRN("Server responded with obsolete block number.");
116 ack_count++;
117 continue; /* duplicated ACK */
118 } else if (opcode == ERROR_OPCODE) {
119 if (client->callback) {
120 struct tftp_evt evt = {
121 .type = TFTP_EVT_ERROR
122 };
123
124 evt.param.error.msg = client->tftp_buf + TFTP_HEADER_SIZE;
125 evt.param.error.code = block_no;
126 client->callback(&evt);
127 }
128 LOG_WRN("Server responded with obsolete block number.");
129 break;
130 } else {
131 LOG_ERR("Server responded with invalid opcode or block number.");
132 break; /* wrong response, re-send data */
133 }
134 } while (true);
135
136 send_count++;
137 } while (true);
138
139 return TFTPC_REMOTE_ERROR;
140 }
141
142 /*
143 * Send an Error Message to the TFTP Server.
144 */
send_err(int sock,struct tftpc * client,int err_code,char * err_msg)145 static inline int send_err(int sock, struct tftpc *client, int err_code, char *err_msg)
146 {
147 uint32_t req_size;
148
149 LOG_DBG("Client sending error code: %d", err_code);
150
151 /* Fill in the "Err" Opcode and the actual error code. */
152 sys_put_be16(ERROR_OPCODE, client->tftp_buf);
153 sys_put_be16(err_code, client->tftp_buf + 2);
154 req_size = 4;
155
156 /* Copy the Error String. */
157 if (err_msg != NULL) {
158 size_t copy_len = strlen(err_msg);
159
160 if (copy_len > sizeof(client->tftp_buf) - req_size) {
161 copy_len = sizeof(client->tftp_buf) - req_size;
162 }
163
164 memcpy(client->tftp_buf + req_size, err_msg, copy_len);
165 req_size += copy_len;
166 }
167
168 /* Send Error to server. */
169 return zsock_send(sock, client->tftp_buf, req_size, 0);
170 }
171
172 /*
173 * Send an Ack Message to the TFTP Server.
174 */
send_ack(int sock,struct tftphdr_ack * ackhdr)175 static inline int send_ack(int sock, struct tftphdr_ack *ackhdr)
176 {
177 LOG_DBG("Client acking block number: %d", ntohs(ackhdr->block));
178
179 return zsock_send(sock, ackhdr, sizeof(struct tftphdr_ack), 0);
180 }
181
send_request(int sock,struct tftpc * client,int request,const char * remote_file,const char * mode)182 static int send_request(int sock, struct tftpc *client,
183 int request, const char *remote_file, const char *mode)
184 {
185 int tx_count = 0;
186 size_t req_size;
187 int ret;
188
189 /* Create TFTP Request. */
190 req_size = make_request(client->tftp_buf, request, remote_file, mode);
191
192 do {
193 tx_count++;
194
195 LOG_DBG("Sending TFTP request %d file %s", request,
196 remote_file);
197
198 /* Send the request to the server */
199 ret = zsock_sendto(sock, client->tftp_buf, req_size, 0, &client->server,
200 ADDRLEN(client->server));
201 if (ret < 0) {
202 break;
203 }
204
205 /* Poll for the response */
206 struct zsock_pollfd fds = {
207 .fd = sock,
208 .events = ZSOCK_POLLIN,
209 };
210
211 ret = zsock_poll(&fds, 1, CONFIG_TFTPC_REQUEST_TIMEOUT);
212 if (ret <= 0) {
213 LOG_DBG("Failed to get data from the TFTP Server"
214 ", req. no. %d", tx_count);
215 continue;
216 }
217
218 /* Receive data from the TFTP Server. */
219 struct sockaddr from_addr;
220 socklen_t from_addr_len = sizeof(from_addr);
221
222 ret = zsock_recvfrom(sock, client->tftp_buf, TFTPC_MAX_BUF_SIZE, 0,
223 &from_addr, &from_addr_len);
224 if (ret < TFTP_HEADER_SIZE) {
225 req_size = make_request(client->tftp_buf, request,
226 remote_file, mode);
227 continue;
228 }
229
230 /* Limit communication to the specific address:port */
231 if (zsock_connect(sock, &from_addr, from_addr_len) < 0) {
232 ret = -errno;
233 LOG_ERR("connect failed, err %d", ret);
234 break;
235 }
236
237 break;
238
239 } while (tx_count <= TFTP_REQ_RETX);
240
241 return ret;
242 }
243
tftp_get(struct tftpc * client,const char * remote_file,const char * mode)244 int tftp_get(struct tftpc *client, const char *remote_file, const char *mode)
245 {
246 int sock;
247 uint32_t tftpc_block_no = 1;
248 uint32_t tftpc_index = 0;
249 int tx_count = 0;
250 struct tftphdr_ack ackhdr = {
251 .opcode = htons(ACK_OPCODE),
252 .block = htons(1)
253 };
254 int rcv_size;
255 int ret;
256
257 if (client == NULL) {
258 return -EINVAL;
259 }
260
261 sock = zsock_socket(client->server.sa_family, SOCK_DGRAM, IPPROTO_UDP);
262 if (sock < 0) {
263 LOG_ERR("Failed to create UDP socket: %d", errno);
264 return -errno;
265 }
266
267 /* Send out the READ request to the TFTP Server. */
268 ret = send_request(sock, client, READ_REQUEST, remote_file, mode);
269 rcv_size = ret;
270
271 while (rcv_size >= TFTP_HEADER_SIZE && rcv_size <= TFTPC_MAX_BUF_SIZE) {
272 /* Process server response. */
273 uint16_t opcode = sys_get_be16(client->tftp_buf);
274 uint16_t block_no = sys_get_be16(client->tftp_buf + 2);
275
276 LOG_DBG("Received data: opcode %u, block no %u, size %d",
277 opcode, block_no, rcv_size);
278
279 if (opcode == ERROR_OPCODE) {
280 if (client->callback) {
281 struct tftp_evt evt = {
282 .type = TFTP_EVT_ERROR
283 };
284
285 evt.param.error.msg = client->tftp_buf + TFTP_HEADER_SIZE;
286 evt.param.error.code = block_no;
287 client->callback(&evt);
288 }
289 ret = TFTPC_REMOTE_ERROR;
290 break;
291 } else if (opcode != DATA_OPCODE) {
292 LOG_ERR("Server responded with invalid opcode.");
293 ret = TFTPC_REMOTE_ERROR;
294 break;
295 }
296
297 if (block_no == tftpc_block_no) {
298 uint32_t data_size = rcv_size - TFTP_HEADER_SIZE;
299
300 tftpc_block_no++;
301 ackhdr.block = htons(block_no);
302 tx_count = 0;
303
304 if (client->callback == NULL) {
305 LOG_ERR("No callback defined.");
306 if (send_err(sock, client, TFTP_ERROR_DISK_FULL, NULL) < 0) {
307 LOG_ERR("Failed to send error response, err: %d",
308 -errno);
309 }
310 ret = TFTPC_BUFFER_OVERFLOW;
311 goto get_end;
312 }
313
314 /* Send received data to client */
315 struct tftp_evt evt = {
316 .type = TFTP_EVT_DATA
317 };
318
319 evt.param.data.data_ptr = client->tftp_buf + TFTP_HEADER_SIZE;
320 evt.param.data.len = data_size;
321 client->callback(&evt);
322
323 /* Update the index. */
324 tftpc_index += data_size;
325
326 /* Per RFC1350, the end of a transfer is marked
327 * by datagram size < TFTPC_MAX_BUF_SIZE.
328 */
329 if (rcv_size < TFTPC_MAX_BUF_SIZE) {
330 (void)send_ack(sock, &ackhdr);
331 ret = tftpc_index;
332 LOG_DBG("%d bytes received.", tftpc_index);
333 /* RFC1350: The host acknowledging the final DATA packet may
334 * terminate its side of the connection on sending the final ACK.
335 */
336 break;
337 }
338 }
339
340 /* Poll for the response */
341 struct zsock_pollfd fds = {
342 .fd = sock,
343 .events = ZSOCK_POLLIN,
344 };
345
346 do {
347 if (tx_count > TFTP_REQ_RETX) {
348 LOG_ERR("No more retransmits. Exiting");
349 ret = TFTPC_RETRIES_EXHAUSTED;
350 goto get_end;
351 }
352
353 /* Send ACK to the TFTP Server */
354 (void)send_ack(sock, &ackhdr);
355 tx_count++;
356 } while (zsock_poll(&fds, 1, CONFIG_TFTPC_REQUEST_TIMEOUT) <= 0);
357
358 /* Receive data from the TFTP Server. */
359 ret = zsock_recv(sock, client->tftp_buf, TFTPC_MAX_BUF_SIZE, 0);
360 rcv_size = ret;
361 }
362
363 if (!(rcv_size >= TFTP_HEADER_SIZE && rcv_size <= TFTPC_MAX_BUF_SIZE)) {
364 ret = TFTPC_REMOTE_ERROR;
365 }
366
367 get_end:
368 zsock_close(sock);
369 return ret;
370 }
371
tftp_put(struct tftpc * client,const char * remote_file,const char * mode,const uint8_t * user_buf,uint32_t user_buf_size)372 int tftp_put(struct tftpc *client, const char *remote_file, const char *mode,
373 const uint8_t *user_buf, uint32_t user_buf_size)
374 {
375 int sock;
376 uint32_t tftpc_block_no = 1;
377 uint32_t tftpc_index = 0;
378 uint32_t send_size;
379 uint8_t *send_buffer;
380 int ret;
381
382 if (client == NULL || user_buf == NULL || user_buf_size == 0) {
383 return -EINVAL;
384 }
385
386 sock = zsock_socket(client->server.sa_family, SOCK_DGRAM, IPPROTO_UDP);
387 if (sock < 0) {
388 LOG_ERR("Failed to create UDP socket: %d", errno);
389 return -errno;
390 }
391
392 /* Send out the WRITE request to the TFTP Server. */
393 ret = send_request(sock, client, WRITE_REQUEST, remote_file, mode);
394
395 /* Check connection initiation result */
396 if (ret >= TFTP_HEADER_SIZE) {
397 uint16_t opcode = sys_get_be16(client->tftp_buf);
398 uint16_t block_no = sys_get_be16(client->tftp_buf + 2);
399
400 LOG_DBG("Receive: opcode %u, block no %u, size %d", opcode, block_no, ret);
401
402 if (opcode == ERROR_OPCODE) {
403 if (client->callback) {
404 struct tftp_evt evt = {
405 .type = TFTP_EVT_ERROR
406 };
407
408 evt.param.error.msg = client->tftp_buf + TFTP_HEADER_SIZE;
409 evt.param.error.code = block_no;
410 client->callback(&evt);
411 }
412 LOG_ERR("Server responded with service reject.");
413 ret = TFTPC_REMOTE_ERROR;
414 goto put_end;
415 } else if (opcode != ACK_OPCODE || block_no != 0) {
416 LOG_ERR("Server responded with invalid opcode or block number.");
417 ret = TFTPC_REMOTE_ERROR;
418 goto put_end;
419 }
420 } else {
421 ret = TFTPC_REMOTE_ERROR;
422 goto put_end;
423 }
424
425 /* Send out data by chunks */
426 do {
427 send_size = user_buf_size - tftpc_index;
428 if (send_size > TFTP_BLOCK_SIZE) {
429 send_size = TFTP_BLOCK_SIZE;
430 }
431 send_buffer = (uint8_t *)(user_buf + tftpc_index);
432
433 ret = send_data(sock, client, tftpc_block_no, send_buffer, send_size);
434 if (ret != TFTPC_SUCCESS) {
435 goto put_end;
436 } else {
437 tftpc_index += send_size;
438 tftpc_block_no++;
439 }
440
441 /* Per RFC1350, the end of a transfer is marked
442 * by datagram size < TFTPC_MAX_BUF_SIZE.
443 */
444 if (send_size < TFTP_BLOCK_SIZE) {
445 LOG_DBG("%d bytes sent.", tftpc_index);
446 ret = tftpc_index;
447 break;
448 }
449 } while (true);
450
451 put_end:
452 zsock_close(sock);
453 return ret;
454 }
455