2 * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/ioctl.h>
33 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/tftp.h>
43 #include "tftp-file.h"
45 #include "tftp-utils.h"
46 #include "tftp-options.h"
47 #include "tftp-transfer.h"
50 * Send a file via the TFTP data session.
53 tftp_send(int peer, uint16_t *block, struct tftp_stats *ts)
56 int size, n_data, n_ack, try;
58 char sendbuffer[MAXPKTSIZE];
59 char recvbuffer[MAXPKTSIZE];
61 rp = (struct tftphdr *)recvbuffer;
65 if (debug&DEBUG_SIMPLE)
66 tftp_log(LOG_DEBUG, "Sending block %d", *block);
68 size = read_file(sendbuffer, segsize);
70 tftp_log(LOG_ERR, "read_file returned %d", size);
71 send_error(peer, errno + 100);
75 for (try = 0; ; try++) {
76 n_data = send_data(peer, *block, sendbuffer, size);
78 if (try == maxtimeouts) {
80 "Cannot send DATA packet #%d, "
85 "Cannot send DATA packet #%d, trying again",
90 n_ack = receive_packet(peer, recvbuffer,
91 MAXPKTSIZE, NULL, timeoutpacket);
93 if (n_ack == RP_TIMEOUT) {
94 if (try == maxtimeouts) {
96 "Timeout #%d send ACK %d "
97 "giving up", try, *block);
100 tftp_log(LOG_WARNING,
101 "Timeout #%d on ACK %d",
106 /* Either read failure or ERROR packet */
107 if (debug&DEBUG_SIMPLE)
108 tftp_log(LOG_ERR, "Aborting: %s",
112 if (rp->th_opcode == ACK) {
114 if (rp->th_block == *block) {
119 /* Re-synchronize with the other side */
120 (void) synchnet(peer);
121 if (rp->th_block == (*block - 1)) {
130 if (oldblock > *block) {
131 if (options[OPT_ROLLOVER].o_request == NULL) {
133 "Block rollover but not allowed.");
134 send_error(peer, EBADOP);
135 gettimeofday(&(ts->tstop), NULL);
139 *block = atoi(options[OPT_ROLLOVER].o_request);
142 gettimeofday(&(ts->tstop), NULL);
143 } while (size == segsize);
149 * Receive a file via the TFTP data session.
151 * - It could be that the first block has already arrived while
152 * trying to figure out if we were receiving options or not. In
153 * that case it is passed to this function.
156 tftp_receive(int peer, uint16_t *block, struct tftp_stats *ts,
157 struct tftphdr *firstblock, size_t fb_size)
161 int n_data, n_ack, writesize, i, retry;
162 char recvbuffer[MAXPKTSIZE];
166 if (firstblock != NULL) {
167 writesize = write_file(firstblock->th_data, fb_size);
168 ts->amount += writesize;
170 n_ack = send_ack(peer, *block);
172 if (i == maxtimeouts) {
174 "Cannot send ACK packet #%d, "
175 "giving up", *block);
179 "Cannot send ACK packet #%d, trying again",
187 if (fb_size != segsize) {
188 gettimeofday(&(ts->tstop), NULL);
193 rp = (struct tftphdr *)recvbuffer;
197 if (oldblock > *block) {
198 if (options[OPT_ROLLOVER].o_request == NULL) {
200 "Block rollover but not allowed.");
201 send_error(peer, EBADOP);
202 gettimeofday(&(ts->tstop), NULL);
206 *block = atoi(options[OPT_ROLLOVER].o_request);
210 for (retry = 0; ; retry++) {
211 if (debug&DEBUG_SIMPLE)
213 "Receiving DATA block %d", *block);
215 n_data = receive_packet(peer, recvbuffer,
216 MAXPKTSIZE, NULL, timeoutpacket);
218 if (retry == maxtimeouts) {
220 "Timeout #%d on DATA block %d, "
221 "giving up", retry, *block);
224 if (n_data == RP_TIMEOUT) {
225 tftp_log(LOG_WARNING,
226 "Timeout #%d on DATA block %d",
228 send_ack(peer, oldblock);
232 /* Either read failure or ERROR packet */
233 if (debug&DEBUG_SIMPLE)
234 tftp_log(LOG_DEBUG, "Aborting: %s",
235 rp_strerror(n_data));
238 if (rp->th_opcode == DATA) {
241 if (rp->th_block == *block)
244 tftp_log(LOG_WARNING,
245 "Expected DATA block %d, got block %d",
246 *block, rp->th_block);
248 /* Re-synchronize with the other side */
249 (void) synchnet(peer);
250 if (rp->th_block == (*block-1)) {
251 tftp_log(LOG_INFO, "Trying to sync");
254 goto send_ack; /* rexmit */
258 tftp_log(LOG_WARNING,
259 "Expected DATA block, got %s block",
260 packettype(rp->th_opcode));
265 writesize = write_file(rp->th_data, n_data);
266 ts->amount += writesize;
267 if (writesize <= 0) {
269 "write_file returned %d", writesize);
271 send_error(peer, errno + 100);
273 send_error(peer, ENOSPACE);
280 n_ack = send_ack(peer, *block);
283 if (i == maxtimeouts) {
285 "Cannot send ACK packet #%d, "
286 "giving up", *block);
291 "Cannot send ACK packet #%d, trying again",
298 gettimeofday(&(ts->tstop), NULL);
299 } while (n_data == segsize);
301 /* Don't do late packet management for the client implementation */
302 if (acting_as_client)
306 n_data = receive_packet(peer, (char *)rp, pktsize,
307 NULL, timeoutpacket);
311 rp->th_opcode == DATA && /* and got a data block */
312 *block == rp->th_block) /* then my last ack was lost */
313 send_ack(peer, *block); /* resend final ack */