4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
39 #pragma ident "%Z%%M% %I% %E% SMI"
42 * TFTP User Program -- Protocol Machines
44 #include <sys/types.h>
45 #include <sys/socket.h>
48 #include <sys/param.h>
59 #include "tftpcommon.h"
60 #include "tftpprivate.h"
62 static char *blksize_str(void);
63 static char *timeout_str(void);
64 static char *tsize_str(void);
65 static int blksize_handler(char *);
66 static int timeout_handler(char *);
67 static int tsize_handler(char *);
68 static int add_options(char *, char *);
69 static int process_oack(tftpbuf
*, int);
71 static void startclock(void);
72 static void stopclock(void);
73 static void printstats(char *, off_t
);
74 static int makerequest(int, char *, struct tftphdr
*, char *);
75 static void tpacket(char *, struct tftphdr
*, int);
77 static struct options
{
79 char *(*opt_str
)(void);
80 int (*opt_handler
)(char *);
82 { "blksize", blksize_str
, blksize_handler
},
83 { "timeout", timeout_str
, timeout_handler
},
84 { "tsize", tsize_str
, tsize_handler
},
88 static char optbuf
[MAX_OPTVAL_LEN
];
89 static boolean_t tsize_set
;
91 static tftpbuf ackbuf
;
94 static jmp_buf timeoutbuf
;
96 int blocksize
= SEGSIZE
; /* Number of data bytes in a DATA packet */
103 if (timeout
>= maxtimeout
) {
104 (void) fputs("Transfer timed out.\n", stderr
);
105 longjmp(toplevel
, -1);
107 (void) signal(SIGALRM
, timer
);
108 longjmp(timeoutbuf
, 1);
112 * Send the requested file.
115 tftp_sendfile(int fd
, char *name
, char *mode
)
117 struct tftphdr
*ap
; /* data and ack packets */
119 int count
= 0, size
, n
;
122 struct sockaddr_in6 from
;
124 int convert
; /* true if doing nl->crlf conversion */
129 startclock(); /* start stat's clock */
130 dp
= r_init(); /* reset fillbuf/read-ahead code */
132 file
= fdopen(fd
, "r");
133 convert
= (strcmp(mode
, "netascii") == 0);
135 tsize_set
= ((tsize_opt
!= 0) && !convert
&& (fstat(fd
, &statb
) == 0));
137 tsize
= statb
.st_size
;
140 (void) signal(SIGALRM
, timer
);
142 if ((size
= makerequest(WRQ
, name
, dp
, mode
)) == -1) {
143 (void) fprintf(stderr
,
144 "tftp: Error: Write request packet too "
151 size
= readit(file
, &dp
, convert
);
156 dp
->th_opcode
= htons((ushort_t
)DATA
);
157 dp
->th_block
= htons((ushort_t
)block
);
160 (void) setjmp(timeoutbuf
);
162 tpacket("sent", dp
, size
+ 4);
163 n
= sendto(f
, dp
, size
+ 4, 0,
164 (struct sockaddr
*)&sin6
, sizeof (sin6
));
166 perror("tftp: sendto");
169 /* Can't read-ahead first block as OACK may change blocksize */
171 read_ahead(file
, convert
);
172 (void) alarm(rexmtval
);
174 (void) sigrelse(SIGALRM
);
176 fromlen
= (socklen_t
)sizeof (from
);
177 n
= recvfrom(f
, ackbuf
.tb_data
,
178 sizeof (ackbuf
.tb_data
), 0,
179 (struct sockaddr
*)&from
, &fromlen
);
181 perror("tftp: recvfrom");
184 } while (n
< offsetof(struct tftphdr
, th_data
));
185 (void) sighold(SIGALRM
);
186 sin6
.sin6_port
= from
.sin6_port
; /* added */
188 tpacket("received", ap
, n
);
189 /* should verify packet came from server */
190 ap
->th_opcode
= ntohs(ap
->th_opcode
);
191 if (ap
->th_opcode
== ERROR
) {
192 ap
->th_code
= ntohs(ap
->th_code
);
193 (void) fprintf(stderr
,
194 "Error code %d", ap
->th_code
);
195 if (n
> offsetof(struct tftphdr
, th_data
))
196 (void) fprintf(stderr
, ": %.*s", n
-
197 offsetof(struct tftphdr
, th_data
),
199 (void) fputc('\n', stderr
);
202 if ((count
== 0) && (ap
->th_opcode
== OACK
)) {
203 errcode
= process_oack(&ackbuf
, n
);
206 (void) fputs("Rejected OACK\n",
212 if (ap
->th_opcode
== ACK
) {
213 ap
->th_block
= ntohs(ap
->th_block
);
214 if (ap
->th_block
== block
) {
218 * Never resend the current DATA packet on
219 * receipt of a duplicate ACK, doing so would
220 * cause the "Sorcerer's Apprentice Syndrome".
229 } while (size
== blocksize
|| count
== 1);
235 printstats("Sent", amount
);
242 tftp_recvfile(int fd
, char *name
, char *mode
)
248 unsigned long amount
= 0;
249 struct sockaddr_in6 from
;
251 boolean_t firsttrip
= B_TRUE
;
253 int convert
; /* true if converting crlf -> lf */
259 file
= fdopen(fd
, "w");
260 convert
= (strcmp(mode
, "netascii") == 0);
262 tsize_set
= (tsize_opt
!= 0);
266 if ((size
= makerequest(RRQ
, name
, ap
, mode
)) == -1) {
267 (void) fprintf(stderr
,
268 "tftp: Error: Read request packet too big\n");
274 (void) signal(SIGALRM
, timer
);
278 ap
->th_opcode
= htons((ushort_t
)ACK
);
279 ap
->th_block
= htons((ushort_t
)(block
));
286 (void) setjmp(timeoutbuf
);
289 tpacket("sent", ap
, size
);
290 if (sendto(f
, ackbuf
.tb_data
, size
, 0, (struct sockaddr
*)&sin6
,
291 sizeof (sin6
)) != size
) {
293 perror("tftp: sendto");
296 if (write_behind(file
, convert
) < 0) {
300 (void) alarm(rexmtval
);
302 (void) sigrelse(SIGALRM
);
304 fromlen
= (socklen_t
)sizeof (from
);
305 n
= recvfrom(f
, dp
, blocksize
+ 4, 0,
306 (struct sockaddr
*)&from
, &fromlen
);
308 perror("tftp: recvfrom");
311 } while (n
< offsetof(struct tftphdr
, th_data
));
312 (void) sighold(SIGALRM
);
313 sin6
.sin6_port
= from
.sin6_port
; /* added */
315 tpacket("received", dp
, n
);
316 /* should verify client address */
317 dp
->th_opcode
= ntohs(dp
->th_opcode
);
318 if (dp
->th_opcode
== ERROR
) {
319 dp
->th_code
= ntohs(dp
->th_code
);
320 (void) fprintf(stderr
, "Error code %d",
322 if (n
> offsetof(struct tftphdr
, th_data
))
323 (void) fprintf(stderr
, ": %.*s", n
-
324 offsetof(struct tftphdr
, th_data
),
326 (void) fputc('\n', stderr
);
329 if ((block
== 1) && (dp
->th_opcode
== OACK
)) {
330 errcode
= process_oack((tftpbuf
*)dp
, n
);
334 (void) fputs("Rejected OACK\n",
339 ap
->th_opcode
= htons((ushort_t
)ACK
);
340 ap
->th_block
= htons(0);
344 if (dp
->th_opcode
== DATA
) {
347 dp
->th_block
= ntohs(dp
->th_block
);
348 if (dp
->th_block
== block
) {
349 break; /* have next packet */
352 * On an error, try to synchronize
357 perror("tftp: recvfrom");
360 if ((j
> 0) && trace
) {
361 (void) printf("discarded %d packets\n",
364 if (dp
->th_block
== (block
-1)) {
365 goto send_ack
; /* resend ack */
370 size
= writeit(file
, &dp
, n
- 4, convert
);
376 } while (size
== blocksize
);
379 if (write_behind(file
, convert
) < 0) { /* flush last buffer */
390 /* ok to ack, since user has seen err msg */
391 ap
->th_opcode
= htons((ushort_t
)ACK
);
392 ap
->th_block
= htons((ushort_t
)block
);
394 tpacket("sent", ap
, 4);
395 if (sendto(f
, ackbuf
.tb_data
, 4, 0,
396 (struct sockaddr
*)&sin6
, sizeof (sin6
)) != 4)
397 perror("tftp: sendto");
405 printstats("Received", amount
);
409 makerequest(int request
, char *name
, struct tftphdr
*tp
, char *mode
)
414 tp
->th_opcode
= htons((ushort_t
)request
);
415 cp
= (char *)&tp
->th_stuff
;
417 /* Maximum size of a request packet is 512 bytes (RFC 2347) */
418 cpend
= (char *)tp
+ SEGSIZE
;
420 len
= strlcpy(cp
, name
, cpend
- cp
) + 1;
425 len
= strlcpy(cp
, mode
, cpend
- cp
) + 1;
430 len
= add_options(cp
, cpend
);
435 return (cp
- (char *)tp
);
439 * Return the blksize option value string to include in the request packet.
448 (void) snprintf(optbuf
, sizeof (optbuf
), "%d", blksize
);
453 * Return the timeout option value string to include in the request packet.
461 (void) snprintf(optbuf
, sizeof (optbuf
), "%d", srexmtval
);
466 * Return the tsize option value string to include in the request packet.
471 if (tsize_set
== B_FALSE
)
474 (void) snprintf(optbuf
, sizeof (optbuf
), OFF_T_FMT
, tsize
);
479 * Validate and action the blksize option value string from the OACK packet.
480 * Returns -1 on success or an error code on failure.
483 blksize_handler(char *optstr
)
488 /* Make sure the option was requested */
492 value
= (int)strtol(optstr
, &endp
, 10);
493 if (errno
!= 0 || value
< MIN_BLKSIZE
|| value
> blksize
||
501 * Validate and action the timeout option value string from the OACK packet.
502 * Returns -1 on success or an error code on failure.
505 timeout_handler(char *optstr
)
510 /* Make sure the option was requested */
514 value
= (int)strtol(optstr
, &endp
, 10);
515 if (errno
!= 0 || value
!= srexmtval
|| *endp
!= '\0')
518 * Nothing to set, client and server retransmission intervals are
519 * set separately in the client.
525 * Validate and action the tsize option value string from the OACK packet.
526 * Returns -1 on success or an error code on failure.
529 tsize_handler(char *optstr
)
534 /* Make sure the option was requested */
535 if (tsize_set
== B_FALSE
)
538 value
= strtoll(optstr
, &endp
, 10);
539 if (errno
!= 0 || value
< 0 || *endp
!= '\0')
541 #if _FILE_OFFSET_BITS == 32
542 if (value
> MAXOFF_T
)
546 * Don't bother checking the tsize value we specified in a write
547 * request is echoed back in the OACK.
555 * Add TFTP options to a request packet.
558 add_options(char *obuf
, char *obufend
)
564 for (i
= 0; options
[i
].opt_name
!= NULL
; i
++) {
565 ostr
= options
[i
].opt_str();
567 cp
+= strlcpy(cp
, options
[i
].opt_name
, obufend
- cp
)
572 cp
+= strlcpy(cp
, ostr
, obufend
- cp
) + 1;
581 * Process OACK packet sent by server in response to options in the request
582 * packet. Returns -1 on success or an error code on failure.
585 process_oack(tftpbuf
*oackbuf
, int n
)
587 char *cp
, *oackend
, *optname
, *optval
;
588 struct tftphdr
*oackp
;
591 oackp
= &oackbuf
->tb_hdr
;
592 cp
= (char *)&oackp
->th_stuff
;
593 oackend
= (char *)oackbuf
+ n
;
595 while (cp
< oackend
) {
597 if ((optval
= next_field(optname
, oackend
)) == NULL
)
599 if ((cp
= next_field(optval
, oackend
)) == NULL
)
601 for (i
= 0; options
[i
].opt_name
!= NULL
; i
++) {
602 if (strcasecmp(optname
, options
[i
].opt_name
) == 0)
605 if (options
[i
].opt_name
== NULL
)
607 errcode
= options
[i
].opt_handler(optval
);
615 * Send a nak packet (error message).
616 * Error code passed in is one of the
617 * standard TFTP codes, or a UNIX errno
628 tp
->th_opcode
= htons((ushort_t
)ERROR
);
629 tp
->th_code
= htons((ushort_t
)error
);
630 for (pe
= errmsgs
; pe
->e_code
>= 0; pe
++)
631 if (pe
->e_code
== error
)
633 if (pe
->e_code
< 0) {
634 pe
->e_msg
= strerror(error
- 100);
635 tp
->th_code
= EUNDEF
;
637 (void) strlcpy(tp
->th_msg
, pe
->e_msg
,
638 sizeof (ackbuf
) - sizeof (struct tftphdr
));
639 length
= strlen(pe
->e_msg
) + 4;
641 tpacket("sent", tp
, length
);
642 if (sendto(f
, ackbuf
.tb_data
, length
, 0,
643 (struct sockaddr
*)&sin6
, sizeof (sin6
)) != length
)
648 tpacket(char *s
, struct tftphdr
*tp
, int n
)
650 static char *opcodes
[] = \
651 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
652 char *cp
, *file
, *mode
;
653 ushort_t op
= ntohs(tp
->th_opcode
);
656 if (op
< RRQ
|| op
> OACK
)
657 (void) printf("%s opcode=%x ", s
, op
);
659 (void) printf("%s %s ", s
, opcodes
[op
]);
664 tpend
= (char *)tp
+ n
;
665 n
-= sizeof (tp
->th_opcode
);
666 file
= (char *)&tp
->th_stuff
;
667 if ((mode
= next_field(file
, tpend
)) == NULL
) {
668 (void) printf("<file=%.*s>\n", n
, file
);
672 if ((cp
= next_field(mode
, tpend
)) == NULL
) {
673 (void) printf("<file=%s, mode=%.*s>\n", file
, n
, mode
);
676 (void) printf("<file=%s, mode=%s", file
, mode
);
679 (void) printf(", options: ");
680 print_options(stdout
, cp
, n
);
686 (void) printf("<block=%d, %d bytes>\n", ntohs(tp
->th_block
),
687 n
- sizeof (tp
->th_opcode
) - sizeof (tp
->th_block
));
691 (void) printf("<block=%d>\n", ntohs(tp
->th_block
));
695 (void) printf("<options: ");
696 print_options(stdout
, (char *)&tp
->th_stuff
,
697 n
- sizeof (tp
->th_opcode
));
702 (void) printf("<code=%d", ntohs(tp
->th_code
));
703 n
= n
- sizeof (tp
->th_opcode
) - sizeof (tp
->th_code
);
705 (void) printf(", msg=%.*s", n
, tp
->th_msg
);
711 static hrtime_t tstart
, tstop
;
716 tstart
= gethrtime();
726 printstats(char *direction
, off_t amount
)
728 hrtime_t delta
, tenths
;
730 delta
= tstop
- tstart
;
731 tenths
= delta
/ (NANOSEC
/ 10);
732 (void) printf("%s " OFF_T_FMT
" bytes in %" PRId64
".%" PRId64
733 " seconds", direction
, amount
, tenths
/ 10, tenths
% 10);
735 (void) printf(" [%" PRId64
" bits/sec]\n",
736 ((hrtime_t
)amount
* 8 * NANOSEC
) / delta
);
738 (void) putchar('\n');