3 /* $OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $ */
4 /* $NetBSD: tftp.c,v 1.5 1995/04/29 05:55:25 cgd Exp $ */
7 * Copyright (c) 1983, 1993
8 * The Regents of the University of California. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 /* static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; */
43 /* static char rcsid[] = "$OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $"; */
44 static const char *rcsid UNUSED
=
48 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
51 * TFTP User Program -- Protocol Machines
55 extern struct sockaddr_in peeraddr
; /* filled in by main */
56 extern int f
; /* the opened socket */
60 extern int maxtimeout
;
62 #define PKTSIZE SEGSIZE+4
66 sigjmp_buf timeoutbuf
;
68 static void nak(int, const char *);
69 static int makerequest(int, const char *, struct tftphdr
*, const char *);
70 static void printstats(const char *, unsigned long);
71 static void startclock(void);
72 static void stopclock(void);
73 static void timer(int);
74 static void tpacket(const char *, struct tftphdr
*, int);
77 * Send the requested file.
80 tftp_sendfile(int fd
, const char *name
, const char *mode
)
82 struct tftphdr
*ap
; /* data and ack packets */
85 volatile int is_request
;
86 volatile u_short block
;
87 volatile int size
, convert
;
88 volatile off_t amount
;
89 struct sockaddr_in from
;
92 u_short ap_opcode
, ap_block
;
94 startclock(); /* start stat's clock */
95 dp
= r_init(); /* reset fillbuf/read-ahead code */
96 ap
= (struct tftphdr
*)ackbuf
;
97 convert
= !strcmp(mode
, "netascii");
98 file
= fdopen(fd
, convert
? "rt" : "rb");
100 is_request
= 1; /* First packet is the actual WRQ */
103 bsd_signal(SIGALRM
, timer
);
106 size
= makerequest(WRQ
, name
, dp
, mode
) - 4;
108 /* size = read(fd, dp->th_data, SEGSIZE); */
109 size
= readit(file
, &dp
, convert
);
111 nak(errno
+ 100, NULL
);
114 dp
->th_opcode
= htons((u_short
)DATA
);
115 dp
->th_block
= htons((u_short
)block
);
118 (void) sigsetjmp(timeoutbuf
,1);
121 tpacket("sent", dp
, size
+ 4);
122 n
= sendto(f
, dp
, size
+ 4, 0,
123 (struct sockaddr
*)&peeraddr
, sizeof(peeraddr
));
125 perror("tftp: sendto");
128 read_ahead(file
, convert
);
132 fromlen
= sizeof(from
);
133 n
= recvfrom(f
, ackbuf
, sizeof(ackbuf
), 0,
134 (struct sockaddr
*)&from
, &fromlen
);
138 perror("tftp: recvfrom");
141 peeraddr
.sin_port
= from
.sin_port
; /* added */
143 tpacket("received", ap
, n
);
144 /* should verify packet came from server */
145 ap_opcode
= ntohs((u_short
)ap
->th_opcode
);
146 ap_block
= ntohs((u_short
)ap
->th_block
);
147 if (ap_opcode
== ERROR
) {
148 printf("Error code %d: %s\n", ap_block
,
152 if (ap_opcode
== ACK
) {
155 if (ap_block
== block
) {
158 /* On an error, try to synchronize
163 printf("discarded %d packets\n",
167 * RFC1129/RFC1350: We MUST NOT re-send the DATA
168 * packet in response to an invalid ACK. Doing so
169 * would cause the Sorcerer's Apprentice bug.
177 } while (size
== SEGSIZE
|| block
== 1);
182 printstats("Sent", amount
);
189 tftp_recvfile(int fd
, const char *name
, const char *mode
)
194 volatile u_short block
;
195 volatile int size
, firsttrip
;
196 volatile unsigned long amount
;
197 struct sockaddr_in from
;
200 volatile int convert
; /* true if converting crlf -> lf */
201 u_short dp_opcode
, dp_block
;
205 ap
= (struct tftphdr
*)ackbuf
;
206 convert
= !strcmp(mode
, "netascii");
207 file
= fdopen(fd
, convert
?"wt":"wb");
212 bsd_signal(SIGALRM
, timer
);
215 size
= makerequest(RRQ
, name
, ap
, mode
);
218 ap
->th_opcode
= htons((u_short
)ACK
);
219 ap
->th_block
= htons((u_short
)block
);
224 (void) sigsetjmp(timeoutbuf
,1);
227 tpacket("sent", ap
, size
);
228 if (sendto(f
, ackbuf
, size
, 0, (struct sockaddr
*)&peeraddr
,
229 sizeof(peeraddr
)) != size
) {
231 perror("tftp: sendto");
234 write_behind(file
, convert
);
238 fromlen
= sizeof(from
);
239 n
= recvfrom(f
, dp
, PKTSIZE
, 0,
240 (struct sockaddr
*)&from
, &fromlen
);
244 perror("tftp: recvfrom");
247 peeraddr
.sin_port
= from
.sin_port
; /* added */
249 tpacket("received", dp
, n
);
250 /* should verify client address */
251 dp_opcode
= ntohs((u_short
)dp
->th_opcode
);
252 dp_block
= ntohs((u_short
)dp
->th_block
);
253 if (dp_opcode
== ERROR
) {
254 printf("Error code %d: %s\n", dp_block
, dp
->th_msg
);
257 if (dp_opcode
== DATA
) {
260 if (dp_block
== block
) {
261 break; /* have next packet */
263 /* On an error, try to synchronize
268 printf("discarded %d packets\n", j
);
270 if (dp_block
== (block
-1)) {
271 goto send_ack
; /* resend ack */
275 /* size = write(fd, dp->th_data, n - 4); */
276 size
= writeit(file
, &dp
, n
- 4, convert
);
278 nak(errno
+ 100, NULL
);
282 } while (size
== SEGSIZE
);
283 abort
: /* ok to ack, since user */
284 ap
->th_opcode
= htons((u_short
)ACK
); /* has seen err msg */
285 ap
->th_block
= htons((u_short
)block
);
286 (void) sendto(f
, ackbuf
, 4, 0, (struct sockaddr
*)&peeraddr
,
288 write_behind(file
, convert
); /* flush last buffer */
292 printstats("Received", amount
);
296 makerequest(int request
, const char *name
,
297 struct tftphdr
*tp
, const char *mode
)
301 tp
->th_opcode
= htons((u_short
)request
);
302 cp
= (char *) &(tp
->th_stuff
);
309 return (cp
- (char *)tp
);
312 static const char * const errmsgs
[] =
314 "Undefined error code", /* 0 - EUNDEF */
315 "File not found", /* 1 - ENOTFOUND */
316 "Access denied", /* 2 - EACCESS */
317 "Disk full or allocation exceeded", /* 3 - ENOSPACE */
318 "Illegal TFTP operation", /* 4 - EBADOP */
319 "Unknown transfer ID", /* 5 - EBADID */
320 "File already exists", /* 6 - EEXISTS */
321 "No such user", /* 7 - ENOUSER */
322 "Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */
324 #define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))
327 * Send a nak packet (error message).
328 * Error code passed in is one of the
329 * standard TFTP codes, or a UNIX errno
333 nak(int error
, const char *msg
)
338 tp
= (struct tftphdr
*)ackbuf
;
339 tp
->th_opcode
= htons((u_short
)ERROR
);
340 tp
->th_code
= htons((u_short
)error
);
342 if ( error
>= 100 ) {
343 /* This is a Unix errno+100 */
345 msg
= strerror(error
- 100);
348 if ( (unsigned)error
>= ERR_CNT
)
352 msg
= errmsgs
[error
];
355 tp
->th_code
= htons((u_short
)error
);
357 length
= strlen(msg
)+1;
358 memcpy(tp
->th_msg
, msg
, length
);
359 length
+= 4; /* Add space for header */
362 tpacket("sent", tp
, length
);
363 if (sendto(f
, ackbuf
, length
, 0, (struct sockaddr
*)&peeraddr
,
364 sizeof(peeraddr
)) != length
)
369 tpacket(const char *s
, struct tftphdr
*tp
, int n
)
371 static const char *opcodes
[] =
372 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
374 u_short op
= ntohs((u_short
)tp
->th_opcode
);
376 if (op
< RRQ
|| op
> ERROR
)
377 printf("%s opcode=%x ", s
, op
);
379 printf("%s %s ", s
, opcodes
[op
]);
385 file
= cp
= (char *) &(tp
->th_stuff
);
386 cp
= strchr(cp
, '\0');
387 printf("<file=%s, mode=%s>\n", file
, cp
+ 1);
391 printf("<block=%d, %d bytes>\n", ntohs(tp
->th_block
), n
- 4);
395 printf("<block=%d>\n", ntohs(tp
->th_block
));
399 printf("<code=%d, msg=%s>\n", ntohs(tp
->th_code
), tp
->th_msg
);
404 struct timeval tstart
;
405 struct timeval tstop
;
410 (void)gettimeofday(&tstart
, NULL
);
417 (void)gettimeofday(&tstop
, NULL
);
421 printstats(const char *direction
, unsigned long amount
)
424 /* compute delta in 1/10's second units */
425 delta
= ((tstop
.tv_sec
*10.)+(tstop
.tv_usec
/100000)) -
426 ((tstart
.tv_sec
*10.)+(tstart
.tv_usec
/100000));
427 delta
= delta
/10.; /* back to seconds */
428 printf("%s %lu bytes in %.1f seconds", direction
, amount
, delta
);
430 printf(" [%.0f bits/sec]", (amount
*8.)/delta
);
437 int save_errno
= errno
;
439 (void)sig
; /* Shut up unused warning */
442 if (timeout
>= maxtimeout
) {
443 printf("Transfer timed out.\n");
445 siglongjmp(toplevel
, -1);
448 siglongjmp(timeoutbuf
, 1);