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>
58 #include "tftpcommon.h"
59 #include "tftpprivate.h"
61 static char *blksize_str(void);
62 static char *timeout_str(void);
63 static char *tsize_str(void);
64 static int blksize_handler(char *);
65 static int timeout_handler(char *);
66 static int tsize_handler(char *);
67 static int add_options(char *, char *);
68 static int process_oack(tftpbuf
*, int);
70 static void startclock(void);
71 static void stopclock(void);
72 static void printstats(char *, off_t
);
73 static int makerequest(int, char *, struct tftphdr
*, char *);
74 static void tpacket(char *, struct tftphdr
*, int);
76 static struct options
{
78 char *(*opt_str
)(void);
79 int (*opt_handler
)(char *);
81 { "blksize", blksize_str
, blksize_handler
},
82 { "timeout", timeout_str
, timeout_handler
},
83 { "tsize", tsize_str
, tsize_handler
},
87 static char optbuf
[MAX_OPTVAL_LEN
];
88 static boolean_t tsize_set
;
90 static tftpbuf ackbuf
;
93 static jmp_buf timeoutbuf
;
95 int blocksize
= SEGSIZE
; /* Number of data bytes in a DATA packet */
102 if (timeout
>= maxtimeout
) {
103 (void) fputs("Transfer timed out.\n", stderr
);
104 longjmp(toplevel
, -1);
106 (void) signal(SIGALRM
, timer
);
107 longjmp(timeoutbuf
, 1);
111 * Send the requested file.
114 tftp_sendfile(int fd
, char *name
, char *mode
)
116 struct tftphdr
*ap
; /* data and ack packets */
118 int count
= 0, size
, n
;
121 struct sockaddr_in6 from
;
123 int convert
; /* true if doing nl->crlf conversion */
128 startclock(); /* start stat's clock */
129 dp
= r_init(); /* reset fillbuf/read-ahead code */
131 file
= fdopen(fd
, "r");
132 convert
= (strcmp(mode
, "netascii") == 0);
134 tsize_set
= ((tsize_opt
!= 0) && !convert
&& (fstat(fd
, &statb
) == 0));
136 tsize
= statb
.st_size
;
139 (void) signal(SIGALRM
, timer
);
141 if ((size
= makerequest(WRQ
, name
, dp
, mode
)) == -1) {
142 (void) fprintf(stderr
,
143 "tftp: Error: Write request packet too "
150 size
= readit(file
, &dp
, convert
);
155 dp
->th_opcode
= htons((ushort_t
)DATA
);
156 dp
->th_block
= htons((ushort_t
)block
);
159 (void) setjmp(timeoutbuf
);
161 tpacket("sent", dp
, size
+ 4);
162 n
= sendto(f
, dp
, size
+ 4, 0,
163 (struct sockaddr
*)&sin6
, sizeof (sin6
));
165 perror("tftp: sendto");
168 /* Can't read-ahead first block as OACK may change blocksize */
170 read_ahead(file
, convert
);
171 (void) alarm(rexmtval
);
173 (void) sigrelse(SIGALRM
);
175 fromlen
= (socklen_t
)sizeof (from
);
176 n
= recvfrom(f
, ackbuf
.tb_data
,
177 sizeof (ackbuf
.tb_data
), 0,
178 (struct sockaddr
*)&from
, &fromlen
);
180 perror("tftp: recvfrom");
183 } while (n
< offsetof(struct tftphdr
, th_data
));
184 (void) sighold(SIGALRM
);
185 sin6
.sin6_port
= from
.sin6_port
; /* added */
187 tpacket("received", ap
, n
);
188 /* should verify packet came from server */
189 ap
->th_opcode
= ntohs(ap
->th_opcode
);
190 if (ap
->th_opcode
== ERROR
) {
191 ap
->th_code
= ntohs(ap
->th_code
);
192 (void) fprintf(stderr
,
193 "Error code %d", ap
->th_code
);
194 if (n
> offsetof(struct tftphdr
, th_data
))
195 (void) fprintf(stderr
, ": %.*s", n
-
196 offsetof(struct tftphdr
, th_data
),
198 (void) fputc('\n', stderr
);
201 if ((count
== 0) && (ap
->th_opcode
== OACK
)) {
202 errcode
= process_oack(&ackbuf
, n
);
205 (void) fputs("Rejected OACK\n",
211 if (ap
->th_opcode
== ACK
) {
212 ap
->th_block
= ntohs(ap
->th_block
);
213 if (ap
->th_block
== block
) {
217 * Never resend the current DATA packet on
218 * receipt of a duplicate ACK, doing so would
219 * cause the "Sorcerer's Apprentice Syndrome".
228 } while (size
== blocksize
|| count
== 1);
234 printstats("Sent", amount
);
241 tftp_recvfile(int fd
, char *name
, char *mode
)
247 unsigned long amount
= 0;
248 struct sockaddr_in6 from
;
250 boolean_t firsttrip
= B_TRUE
;
252 int convert
; /* true if converting crlf -> lf */
258 file
= fdopen(fd
, "w");
259 convert
= (strcmp(mode
, "netascii") == 0);
261 tsize_set
= (tsize_opt
!= 0);
265 if ((size
= makerequest(RRQ
, name
, ap
, mode
)) == -1) {
266 (void) fprintf(stderr
,
267 "tftp: Error: Read request packet too big\n");
273 (void) signal(SIGALRM
, timer
);
277 ap
->th_opcode
= htons((ushort_t
)ACK
);
278 ap
->th_block
= htons((ushort_t
)(block
));
285 (void) setjmp(timeoutbuf
);
288 tpacket("sent", ap
, size
);
289 if (sendto(f
, ackbuf
.tb_data
, size
, 0, (struct sockaddr
*)&sin6
,
290 sizeof (sin6
)) != size
) {
292 perror("tftp: sendto");
295 if (write_behind(file
, convert
) < 0) {
299 (void) alarm(rexmtval
);
301 (void) sigrelse(SIGALRM
);
303 fromlen
= (socklen_t
)sizeof (from
);
304 n
= recvfrom(f
, dp
, blocksize
+ 4, 0,
305 (struct sockaddr
*)&from
, &fromlen
);
307 perror("tftp: recvfrom");
310 } while (n
< offsetof(struct tftphdr
, th_data
));
311 (void) sighold(SIGALRM
);
312 sin6
.sin6_port
= from
.sin6_port
; /* added */
314 tpacket("received", dp
, n
);
315 /* should verify client address */
316 dp
->th_opcode
= ntohs(dp
->th_opcode
);
317 if (dp
->th_opcode
== ERROR
) {
318 dp
->th_code
= ntohs(dp
->th_code
);
319 (void) fprintf(stderr
, "Error code %d",
321 if (n
> offsetof(struct tftphdr
, th_data
))
322 (void) fprintf(stderr
, ": %.*s", n
-
323 offsetof(struct tftphdr
, th_data
),
325 (void) fputc('\n', stderr
);
328 if ((block
== 1) && (dp
->th_opcode
== OACK
)) {
329 errcode
= process_oack((tftpbuf
*)dp
, n
);
333 (void) fputs("Rejected OACK\n",
338 ap
->th_opcode
= htons((ushort_t
)ACK
);
339 ap
->th_block
= htons(0);
343 if (dp
->th_opcode
== DATA
) {
346 dp
->th_block
= ntohs(dp
->th_block
);
347 if (dp
->th_block
== block
) {
348 break; /* have next packet */
351 * On an error, try to synchronize
356 perror("tftp: recvfrom");
359 if ((j
> 0) && trace
) {
360 (void) printf("discarded %d packets\n",
363 if (dp
->th_block
== (block
-1)) {
364 goto send_ack
; /* resend ack */
369 size
= writeit(file
, &dp
, n
- 4, convert
);
375 } while (size
== blocksize
);
378 if (write_behind(file
, convert
) < 0) { /* flush last buffer */
389 /* ok to ack, since user has seen err msg */
390 ap
->th_opcode
= htons((ushort_t
)ACK
);
391 ap
->th_block
= htons((ushort_t
)block
);
393 tpacket("sent", ap
, 4);
394 if (sendto(f
, ackbuf
.tb_data
, 4, 0,
395 (struct sockaddr
*)&sin6
, sizeof (sin6
)) != 4)
396 perror("tftp: sendto");
404 printstats("Received", amount
);
408 makerequest(int request
, char *name
, struct tftphdr
*tp
, char *mode
)
413 tp
->th_opcode
= htons((ushort_t
)request
);
414 cp
= (char *)&tp
->th_stuff
;
416 /* Maximum size of a request packet is 512 bytes (RFC 2347) */
417 cpend
= (char *)tp
+ SEGSIZE
;
419 len
= strlcpy(cp
, name
, cpend
- cp
) + 1;
424 len
= strlcpy(cp
, mode
, cpend
- cp
) + 1;
429 len
= add_options(cp
, cpend
);
434 return (cp
- (char *)tp
);
438 * Return the blksize option value string to include in the request packet.
447 (void) snprintf(optbuf
, sizeof (optbuf
), "%d", blksize
);
452 * Return the timeout option value string to include in the request packet.
460 (void) snprintf(optbuf
, sizeof (optbuf
), "%d", srexmtval
);
465 * Return the tsize option value string to include in the request packet.
470 if (tsize_set
== B_FALSE
)
473 (void) snprintf(optbuf
, sizeof (optbuf
), OFF_T_FMT
, tsize
);
478 * Validate and action the blksize option value string from the OACK packet.
479 * Returns -1 on success or an error code on failure.
482 blksize_handler(char *optstr
)
487 /* Make sure the option was requested */
491 value
= (int)strtol(optstr
, &endp
, 10);
492 if (errno
!= 0 || value
< MIN_BLKSIZE
|| value
> blksize
||
500 * Validate and action the timeout option value string from the OACK packet.
501 * Returns -1 on success or an error code on failure.
504 timeout_handler(char *optstr
)
509 /* Make sure the option was requested */
513 value
= (int)strtol(optstr
, &endp
, 10);
514 if (errno
!= 0 || value
!= srexmtval
|| *endp
!= '\0')
517 * Nothing to set, client and server retransmission intervals are
518 * set separately in the client.
524 * Validate and action the tsize option value string from the OACK packet.
525 * Returns -1 on success or an error code on failure.
528 tsize_handler(char *optstr
)
533 /* Make sure the option was requested */
534 if (tsize_set
== B_FALSE
)
537 value
= strtoll(optstr
, &endp
, 10);
538 if (errno
!= 0 || value
< 0 || *endp
!= '\0')
540 #if _FILE_OFFSET_BITS == 32
541 if (value
> MAXOFF_T
)
545 * Don't bother checking the tsize value we specified in a write
546 * request is echoed back in the OACK.
554 * Add TFTP options to a request packet.
557 add_options(char *obuf
, char *obufend
)
563 for (i
= 0; options
[i
].opt_name
!= NULL
; i
++) {
564 ostr
= options
[i
].opt_str();
566 cp
+= strlcpy(cp
, options
[i
].opt_name
, obufend
- cp
)
571 cp
+= strlcpy(cp
, ostr
, obufend
- cp
) + 1;
580 * Process OACK packet sent by server in response to options in the request
581 * packet. Returns -1 on success or an error code on failure.
584 process_oack(tftpbuf
*oackbuf
, int n
)
586 char *cp
, *oackend
, *optname
, *optval
;
587 struct tftphdr
*oackp
;
590 oackp
= &oackbuf
->tb_hdr
;
591 cp
= (char *)&oackp
->th_stuff
;
592 oackend
= (char *)oackbuf
+ n
;
594 while (cp
< oackend
) {
596 if ((optval
= next_field(optname
, oackend
)) == NULL
)
598 if ((cp
= next_field(optval
, oackend
)) == NULL
)
600 for (i
= 0; options
[i
].opt_name
!= NULL
; i
++) {
601 if (strcasecmp(optname
, options
[i
].opt_name
) == 0)
604 if (options
[i
].opt_name
== NULL
)
606 errcode
= options
[i
].opt_handler(optval
);
614 * Send a nak packet (error message).
615 * Error code passed in is one of the
616 * standard TFTP codes, or a UNIX errno
627 tp
->th_opcode
= htons((ushort_t
)ERROR
);
628 tp
->th_code
= htons((ushort_t
)error
);
629 for (pe
= errmsgs
; pe
->e_code
>= 0; pe
++)
630 if (pe
->e_code
== error
)
632 if (pe
->e_code
< 0) {
633 pe
->e_msg
= strerror(error
- 100);
634 tp
->th_code
= EUNDEF
;
636 (void) strlcpy(tp
->th_msg
, pe
->e_msg
,
637 sizeof (ackbuf
) - sizeof (struct tftphdr
));
638 length
= strlen(pe
->e_msg
) + 4;
640 tpacket("sent", tp
, length
);
641 if (sendto(f
, ackbuf
.tb_data
, length
, 0,
642 (struct sockaddr
*)&sin6
, sizeof (sin6
)) != length
)
647 tpacket(char *s
, struct tftphdr
*tp
, int n
)
649 static char *opcodes
[] = \
650 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
651 char *cp
, *file
, *mode
;
652 ushort_t op
= ntohs(tp
->th_opcode
);
655 if (op
< RRQ
|| op
> OACK
)
656 (void) printf("%s opcode=%x ", s
, op
);
658 (void) printf("%s %s ", s
, opcodes
[op
]);
663 tpend
= (char *)tp
+ n
;
664 n
-= sizeof (tp
->th_opcode
);
665 file
= (char *)&tp
->th_stuff
;
666 if ((mode
= next_field(file
, tpend
)) == NULL
) {
667 (void) printf("<file=%.*s>\n", n
, file
);
671 if ((cp
= next_field(mode
, tpend
)) == NULL
) {
672 (void) printf("<file=%s, mode=%.*s>\n", file
, n
, mode
);
675 (void) printf("<file=%s, mode=%s", file
, mode
);
678 (void) printf(", options: ");
679 print_options(stdout
, cp
, n
);
685 (void) printf("<block=%d, %d bytes>\n", ntohs(tp
->th_block
),
686 n
- sizeof (tp
->th_opcode
) - sizeof (tp
->th_block
));
690 (void) printf("<block=%d>\n", ntohs(tp
->th_block
));
694 (void) printf("<options: ");
695 print_options(stdout
, (char *)&tp
->th_stuff
,
696 n
- sizeof (tp
->th_opcode
));
701 (void) printf("<code=%d", ntohs(tp
->th_code
));
702 n
= n
- sizeof (tp
->th_opcode
) - sizeof (tp
->th_code
);
704 (void) printf(", msg=%.*s", n
, tp
->th_msg
);
710 static hrtime_t tstart
, tstop
;
715 tstart
= gethrtime();
725 printstats(char *direction
, off_t amount
)
727 hrtime_t delta
, tenths
;
729 delta
= tstop
- tstart
;
730 tenths
= delta
/ (NANOSEC
/ 10);
731 (void) printf("%s " OFF_T_FMT
" bytes in %" PRId64
".%" PRId64
732 " seconds", direction
, amount
, tenths
/ 10, tenths
% 10);
734 (void) printf(" [%" PRId64
" bits/sec]\n",
735 ((hrtime_t
)amount
* 8 * NANOSEC
) / delta
);
737 (void) putchar('\n');