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 /* 133 * "rollover" option not specified in 134 * tftp client. Default to rolling block 135 * counter to 0. 136 */ 137 *block = 0; 138 } else { 139 *block = atoi(options[OPT_ROLLOVER].o_request); 140 } 141 142 ts->rollovers++; 143 } 144 gettimeofday(&(ts->tstop), NULL); 145 } while (size == segsize); 146 abort: 147 return; 148 } 149 150 /* 151 * Receive a file via the TFTP data session. 152 * 153 * - It could be that the first block has already arrived while 154 * trying to figure out if we were receiving options or not. In 155 * that case it is passed to this function. 156 */ 157 void 158 tftp_receive(int peer, uint16_t *block, struct tftp_stats *ts, 159 struct tftphdr *firstblock, size_t fb_size) 160 { 161 struct tftphdr *rp; 162 uint16_t oldblock; 163 int n_data, n_ack, writesize, i, retry; 164 char recvbuffer[MAXPKTSIZE]; 165 166 ts->amount = 0; 167 168 if (firstblock != NULL) { 169 writesize = write_file(firstblock->th_data, fb_size); 170 ts->amount += writesize; 171 for (i = 0; ; i++) { 172 n_ack = send_ack(peer, *block); 173 if (n_ack > 0) { 174 if (i == maxtimeouts) { 175 tftp_log(LOG_ERR, 176 "Cannot send ACK packet #%d, " 177 "giving up", *block); 178 return; 179 } 180 tftp_log(LOG_ERR, 181 "Cannot send ACK packet #%d, trying again", 182 *block); 183 continue; 184 } 185 186 break; 187 } 188 189 if (fb_size != segsize) { 190 gettimeofday(&(ts->tstop), NULL); 191 return; 192 } 193 } 194 195 rp = (struct tftphdr *)recvbuffer; 196 do { 197 oldblock = *block; 198 (*block)++; 199 if (oldblock > *block) { 200 if (options[OPT_ROLLOVER].o_request == NULL) { 201 /* 202 * "rollover" option not specified in 203 * tftp client. Default to rolling block 204 * counter to 0. 205 */ 206 *block = 0; 207 } else { 208 *block = atoi(options[OPT_ROLLOVER].o_request); 209 } 210 211 ts->rollovers++; 212 } 213 214 for (retry = 0; ; retry++) { 215 if (debug&DEBUG_SIMPLE) 216 tftp_log(LOG_DEBUG, 217 "Receiving DATA block %d", *block); 218 219 n_data = receive_packet(peer, recvbuffer, 220 MAXPKTSIZE, NULL, timeoutpacket); 221 if (n_data < 0) { 222 if (retry == maxtimeouts) { 223 tftp_log(LOG_ERR, 224 "Timeout #%d on DATA block %d, " 225 "giving up", retry, *block); 226 return; 227 } 228 if (n_data == RP_TIMEOUT) { 229 tftp_log(LOG_WARNING, 230 "Timeout #%d on DATA block %d", 231 retry, *block); 232 send_ack(peer, oldblock); 233 continue; 234 } 235 236 /* Either read failure or ERROR packet */ 237 if (debug&DEBUG_SIMPLE) 238 tftp_log(LOG_DEBUG, "Aborting: %s", 239 rp_strerror(n_data)); 240 goto abort; 241 } 242 if (rp->th_opcode == DATA) { 243 ts->blocks++; 244 245 if (rp->th_block == *block) 246 break; 247 248 tftp_log(LOG_WARNING, 249 "Expected DATA block %d, got block %d", 250 *block, rp->th_block); 251 252 /* Re-synchronize with the other side */ 253 (void) synchnet(peer); 254 if (rp->th_block == (*block-1)) { 255 tftp_log(LOG_INFO, "Trying to sync"); 256 *block = oldblock; 257 ts->retries++; 258 goto send_ack; /* rexmit */ 259 } 260 261 } else { 262 tftp_log(LOG_WARNING, 263 "Expected DATA block, got %s block", 264 packettype(rp->th_opcode)); 265 } 266 } 267 268 if (n_data > 0) { 269 writesize = write_file(rp->th_data, n_data); 270 ts->amount += writesize; 271 if (writesize <= 0) { 272 tftp_log(LOG_ERR, 273 "write_file returned %d", writesize); 274 if (writesize < 0) 275 send_error(peer, errno + 100); 276 else 277 send_error(peer, ENOSPACE); 278 goto abort; 279 } 280 } 281 282 send_ack: 283 for (i = 0; ; i++) { 284 n_ack = send_ack(peer, *block); 285 if (n_ack > 0) { 286 287 if (i == maxtimeouts) { 288 tftp_log(LOG_ERR, 289 "Cannot send ACK packet #%d, " 290 "giving up", *block); 291 return; 292 } 293 294 tftp_log(LOG_ERR, 295 "Cannot send ACK packet #%d, trying again", 296 *block); 297 continue; 298 } 299 300 break; 301 } 302 gettimeofday(&(ts->tstop), NULL); 303 } while (n_data == segsize); 304 305 /* Don't do late packet management for the client implementation */ 306 if (acting_as_client) 307 return; 308 309 for (i = 0; ; i++) { 310 n_data = receive_packet(peer, (char *)rp, pktsize, 311 NULL, timeoutpacket); 312 if (n_data <= 0) 313 break; 314 if (n_data > 0 && 315 rp->th_opcode == DATA && /* and got a data block */ 316 *block == rp->th_block) /* then my last ack was lost */ 317 send_ack(peer, *block); /* resend final ack */ 318 } 319 320 abort: 321 return; 322 } 323