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>
| 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: head/libexec/tftpd/tftp-transfer.c 207614 2010-05-04 13:07:40Z imp $");
| 27__FBSDID("$FreeBSD: head/libexec/tftpd/tftp-transfer.c 224536 2011-07-31 03:12:20Z rodrigc $");
|
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 */ 52void 53tftp_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) {
| 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 */ 52void 53tftp_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;
| 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);
|
137 } 138
| 140 } 141
|
139 *block = atoi(options[OPT_ROLLOVER].o_request);
| |
140 ts->rollovers++; 141 } 142 gettimeofday(&(ts->tstop), NULL); 143 } while (size == segsize); 144abort: 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 */ 155void 156tftp_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) {
| 142 ts->rollovers++; 143 } 144 gettimeofday(&(ts->tstop), NULL); 145 } while (size == segsize); 146abort: 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 */ 157void 158tftp_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) {
|
199 tftp_log(LOG_ERR, 200 "Block rollover but not allowed."); 201 send_error(peer, EBADOP); 202 gettimeofday(&(ts->tstop), NULL); 203 return;
| 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);
|
204 } 205
| 209 } 210
|
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 278send_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 316abort: 317 return; 318}
| 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 282send_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 320abort: 321 return; 322}
|