1 /* 2 * Copyright (C) 2008 Edwin Groothuis. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 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. 12 * 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 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #include <sys/ioctl.h> 32 #include <sys/stat.h> 33 #include <sys/socket.h> 34 35 #include <netinet/in.h> 36 #include <arpa/tftp.h> 37 38 #include <errno.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <syslog.h> 42 43 #include "tftp-file.h" 44 #include "tftp-io.h" 45 #include "tftp-utils.h" 46 #include "tftp-options.h" 47 #include "tftp-transfer.h" 48 49 /* 50 * Send a file via the TFTP data session. 51 */ 52 void 53 tftp_send(int peer, uint16_t *block, struct tftp_stats *ts) 54 { 55 struct tftphdr *rp; 56 int size, n_data, n_ack, try; 57 uint16_t oldblock; 58 char sendbuffer[MAXPKTSIZE]; 59 char recvbuffer[MAXPKTSIZE]; 60 61 rp = (struct tftphdr *)recvbuffer; 62 *block = 1; 63 ts->amount = 0; 64 do { 65 if (debug&DEBUG_SIMPLE) 66 tftp_log(LOG_DEBUG, "Sending block %d", *block); 67 68 size = read_file(sendbuffer, segsize); 69 if (size < 0) { 70 tftp_log(LOG_ERR, "read_file returned %d", size); 71 send_error(peer, errno + 100); 72 goto abort; 73 } 74 75 for (try = 0; ; try++) { 76 n_data = send_data(peer, *block, sendbuffer, size); 77 if (n_data > 0) { 78 if (try == maxtimeouts) { 79 tftp_log(LOG_ERR, 80 "Cannot send DATA packet #%d, " 81 "giving up", *block); 82 return; 83 } 84 tftp_log(LOG_ERR, 85 "Cannot send DATA packet #%d, trying again", 86 *block); 87 continue; 88 } 89 90 n_ack = receive_packet(peer, recvbuffer, 91 MAXPKTSIZE, NULL, timeoutpacket); 92 if (n_ack < 0) { 93 if (n_ack == RP_TIMEOUT) { 94 if (try == maxtimeouts) { 95 tftp_log(LOG_ERR, 96 "Timeout #%d send ACK %d " 97 "giving up", try, *block); 98 return; 99 } 100 tftp_log(LOG_WARNING, 101 "Timeout #%d on ACK %d", 102 try, *block); 103 continue; 104 } 105 106 /* Either read failure or ERROR packet */ 107 if (debug&DEBUG_SIMPLE) 108 tftp_log(LOG_ERR, "Aborting: %s", 109 rp_strerror(n_ack)); 110 goto abort; 111 } 112 if (rp->th_opcode == ACK) { 113 ts->blocks++; 114 if (rp->th_block == *block) { 115 ts->amount += size; 116 break; 117 } 118 119 /* Re-synchronize with the other side */ 120 (void) synchnet(peer); 121 if (rp->th_block == (*block - 1)) { 122 ts->retries++; 123 continue; 124 } 125 } 126 127 } 128 oldblock = *block; 129 (*block)++; 130 if (oldblock > *block) { 131 if (options[OPT_ROLLOVER].o_request == NULL) { 132 tftp_log(LOG_ERR, 133 "Block rollover but not allowed."); 134 send_error(peer, EBADOP); 135 gettimeofday(&(ts->tstop), NULL); 136 return; 137 } 138 139 *block = atoi(options[OPT_ROLLOVER].o_request); 140 ts->rollovers++; 141 } 142 gettimeofday(&(ts->tstop), NULL); 143 } while (size == segsize); 144 abort: 145 return; 146 } 147 148 /* 149 * Receive a file via the TFTP data session. 150 * 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. 154 */ 155 void 156 tftp_receive(int peer, uint16_t *block, struct tftp_stats *ts, 157 struct tftphdr *firstblock, size_t fb_size) 158 { 159 struct tftphdr *rp; 160 uint16_t oldblock; 161 int n_data, n_ack, writesize, i, retry; 162 char recvbuffer[MAXPKTSIZE]; 163 164 ts->amount = 0; 165 166 if (firstblock != NULL) { 167 writesize = write_file(firstblock->th_data, fb_size); 168 ts->amount += writesize; 169 for (i = 0; ; i++) { 170 n_ack = send_ack(peer, *block); 171 if (n_ack > 0) { 172 if (i == maxtimeouts) { 173 tftp_log(LOG_ERR, 174 "Cannot send ACK packet #%d, " 175 "giving up", *block); 176 return; 177 } 178 tftp_log(LOG_ERR, 179 "Cannot send ACK packet #%d, trying again", 180 *block); 181 continue; 182 } 183 184 break; 185 } 186 187 if (fb_size != segsize) { 188 gettimeofday(&(ts->tstop), NULL); 189 return; 190 } 191 } 192 193 rp = (struct tftphdr *)recvbuffer; 194 do { 195 oldblock = *block; 196 (*block)++; 197 if (oldblock > *block) { 198 if (options[OPT_ROLLOVER].o_request == NULL) { 199 tftp_log(LOG_ERR, 200 "Block rollover but not allowed."); 201 send_error(peer, EBADOP); 202 gettimeofday(&(ts->tstop), NULL); 203 return; 204 } 205 206 *block = atoi(options[OPT_ROLLOVER].o_request); 207 ts->rollovers++; 208 } 209 210 for (retry = 0; ; retry++) { 211 if (debug&DEBUG_SIMPLE) 212 tftp_log(LOG_DEBUG, 213 "Receiving DATA block %d", *block); 214 215 n_data = receive_packet(peer, recvbuffer, 216 MAXPKTSIZE, NULL, timeoutpacket); 217 if (n_data < 0) { 218 if (retry == maxtimeouts) { 219 tftp_log(LOG_ERR, 220 "Timeout #%d on DATA block %d, " 221 "giving up", retry, *block); 222 return; 223 } 224 if (n_data == RP_TIMEOUT) { 225 tftp_log(LOG_WARNING, 226 "Timeout #%d on DATA block %d", 227 retry, *block); 228 send_ack(peer, oldblock); 229 continue; 230 } 231 232 /* Either read failure or ERROR packet */ 233 if (debug&DEBUG_SIMPLE) 234 tftp_log(LOG_DEBUG, "Aborting: %s", 235 rp_strerror(n_data)); 236 goto abort; 237 } 238 if (rp->th_opcode == DATA) { 239 ts->blocks++; 240 241 if (rp->th_block == *block) 242 break; 243 244 tftp_log(LOG_WARNING, 245 "Expected DATA block %d, got block %d", 246 *block, rp->th_block); 247 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"); 252 *block = oldblock; 253 ts->retries++; 254 goto send_ack; /* rexmit */ 255 } 256 257 } else { 258 tftp_log(LOG_WARNING, 259 "Expected DATA block, got %s block", 260 packettype(rp->th_opcode)); 261 } 262 } 263 264 if (n_data > 0) { 265 writesize = write_file(rp->th_data, n_data); 266 ts->amount += writesize; 267 if (writesize <= 0) { 268 tftp_log(LOG_ERR, 269 "write_file returned %d", writesize); 270 if (writesize < 0) 271 send_error(peer, errno + 100); 272 else 273 send_error(peer, ENOSPACE); 274 goto abort; 275 } 276 } 277 278 send_ack: 279 for (i = 0; ; i++) { 280 n_ack = send_ack(peer, *block); 281 if (n_ack > 0) { 282 283 if (i == maxtimeouts) { 284 tftp_log(LOG_ERR, 285 "Cannot send ACK packet #%d, " 286 "giving up", *block); 287 return; 288 } 289 290 tftp_log(LOG_ERR, 291 "Cannot send ACK packet #%d, trying again", 292 *block); 293 continue; 294 } 295 296 break; 297 } 298 gettimeofday(&(ts->tstop), NULL); 299 } while (n_data == segsize); 300 301 /* Don't do late packet management for the client implementation */ 302 if (acting_as_client) 303 return; 304 305 for (i = 0; ; i++) { 306 n_data = receive_packet(peer, (char *)rp, pktsize, 307 NULL, timeoutpacket); 308 if (n_data <= 0) 309 break; 310 if (n_data > 0 && 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 */ 314 } 315 316 abort: 317 return; 318 } 319