11590Srgrimes/*
21590Srgrimes * Copyright (c) 1983, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
3093428Sdwmalone#if 0
3193428Sdwmalone#ifndef lint
3293428Sdwmalonestatic char sccsid[] = "@(#)tftp.c	8.1 (Berkeley) 6/6/93";
3393428Sdwmalone#endif /* not lint */
3493428Sdwmalone#endif
3593428Sdwmalone
3687708Smarkm#include <sys/cdefs.h>
3787708Smarkm__FBSDID("$FreeBSD$");
3887708Smarkm
391590Srgrimes/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
401590Srgrimes
411590Srgrimes/*
421590Srgrimes * TFTP User Program -- Protocol Machines
431590Srgrimes */
441590Srgrimes#include <sys/socket.h>
45207607Simp#include <sys/stat.h>
461590Srgrimes
471590Srgrimes#include <netinet/in.h>
481590Srgrimes
491590Srgrimes#include <arpa/tftp.h>
501590Srgrimes
5128202Scharnier#include <err.h>
52207607Simp#include <netdb.h>
531590Srgrimes#include <stdio.h>
54207607Simp#include <stdlib.h>
5533645Sjb#include <string.h>
56207607Simp#include <syslog.h>
571590Srgrimes
58207607Simp#include "tftp.h"
59207607Simp#include "tftp-file.h"
60207607Simp#include "tftp-utils.h"
61207607Simp#include "tftp-io.h"
62207607Simp#include "tftp-transfer.h"
63207607Simp#include "tftp-options.h"
641590Srgrimes
651590Srgrimes/*
661590Srgrimes * Send the requested file.
671590Srgrimes */
681590Srgrimesvoid
69207607Simpxmitfile(int peer, char *port, int fd, char *name, char *mode)
701590Srgrimes{
71207607Simp	struct tftphdr *rp;
72207607Simp	int n, i;
73207607Simp	uint16_t block;
7494443Sume	struct sockaddr_storage serv;	/* valid server port number */
75207607Simp	char recvbuffer[MAXPKTSIZE];
76207607Simp	struct tftp_stats tftp_stats;
771590Srgrimes
78207607Simp	stats_init(&tftp_stats);
79207607Simp
8094443Sume	memset(&serv, 0, sizeof(serv));
81207607Simp	rp = (struct tftphdr *)recvbuffer;
821590Srgrimes
83207607Simp	if (port == NULL) {
84207607Simp		struct servent *se;
85207607Simp		se = getservbyname("tftp", "udp");
86207607Simp		((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port;
87207607Simp	} else
88207607Simp		((struct sockaddr_in *)&peer_sock)->sin_port =
89207607Simp		    htons(atoi(port));
90207607Simp
91207607Simp	for (i = 0; i < 12; i++) {
92207607Simp		struct sockaddr_storage from;
93207607Simp
94207607Simp		/* Tell the other side what we want to do */
95207607Simp		if (debug&DEBUG_SIMPLE)
96207607Simp			printf("Sending %s\n", name);
97207607Simp
98207607Simp		n = send_wrq(peer, name, mode);
99207607Simp		if (n > 0) {
100207607Simp			printf("Cannot send WRQ packet\n");
101207607Simp			return;
1021590Srgrimes		}
103207607Simp
104207607Simp		/*
105207607Simp		 * The first packet we receive has the new destination port
106207607Simp		 * we have to send the next packets to.
107207607Simp		 */
108207607Simp		n = receive_packet(peer, recvbuffer,
109207607Simp		    MAXPKTSIZE, &from, timeoutpacket);
110207607Simp
111207607Simp		/* We got some data! */
112207607Simp		if (n >= 0) {
113207607Simp			((struct sockaddr_in *)&peer_sock)->sin_port =
114207607Simp			    ((struct sockaddr_in *)&from)->sin_port;
115207607Simp			break;
1161590Srgrimes		}
1171590Srgrimes
118207607Simp		/* This should be retried */
119207607Simp		if (n == RP_TIMEOUT) {
120207607Simp			printf("Try %d, didn't receive answer from remote.\n",
121207607Simp			    i + 1);
122207607Simp			continue;
1231590Srgrimes		}
124207607Simp
125207607Simp		/* Everything else is fatal */
126207607Simp		break;
127207607Simp	}
128207607Simp	if (i == 12) {
129207607Simp		printf("Transfer timed out.\n");
130207607Simp		return;
131207607Simp	}
132207607Simp	if (rp->th_opcode == ERROR) {
133207607Simp		printf("Got ERROR, aborted\n");
134207607Simp		return;
135207607Simp	}
136207607Simp
137207607Simp	/*
138207607Simp	 * If the first packet is an OACK instead of an ACK packet,
139207607Simp	 * handle it different.
140207607Simp	 */
141207607Simp	if (rp->th_opcode == OACK) {
142207607Simp		if (!options_rfc_enabled) {
143207607Simp			printf("Got OACK while options are not enabled!\n");
144207607Simp			send_error(peer, EBADOP);
145207607Simp			return;
146207607Simp		}
147207607Simp
148207607Simp		parse_options(peer, rp->th_stuff, n + 2);
149207607Simp	}
150207607Simp
151207607Simp	if (read_init(fd, NULL, mode) < 0) {
152207607Simp		warn("read_init()");
153207607Simp		return;
154207607Simp	}
155207607Simp
156207607Simp	block = 1;
157207607Simp	tftp_send(peer, &block, &tftp_stats);
158207607Simp
159207607Simp	read_close();
160209551Sgavin	if (tftp_stats.amount > 0)
161207607Simp		printstats("Sent", verbose, &tftp_stats);
162207607Simp
163207607Simp	txrx_error = 1;
1641590Srgrimes}
1651590Srgrimes
1661590Srgrimes/*
1671590Srgrimes * Receive a file.
1681590Srgrimes */
1691590Srgrimesvoid
170207607Simprecvfile(int peer, char *port, int fd, char *name, char *mode)
1711590Srgrimes{
172207607Simp	struct tftphdr *rp;
173207607Simp	uint16_t block;
174207607Simp	char recvbuffer[MAXPKTSIZE];
175207607Simp	int n, i;
176207607Simp	struct tftp_stats tftp_stats;
1771590Srgrimes
178207607Simp	stats_init(&tftp_stats);
1791590Srgrimes
180207607Simp	rp = (struct tftphdr *)recvbuffer;
1811590Srgrimes
182207607Simp	if (port == NULL) {
183207607Simp		struct servent *se;
184207607Simp		se = getservbyname("tftp", "udp");
185207607Simp		((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port;
186207607Simp	} else
187207607Simp		((struct sockaddr_in *)&peer_sock)->sin_port =
188207607Simp		    htons(atoi(port));
1891590Srgrimes
190207607Simp	for (i = 0; i < 12; i++) {
191207607Simp		struct sockaddr_storage from;
1921590Srgrimes
193207607Simp		/* Tell the other side what we want to do */
194207607Simp		if (debug&DEBUG_SIMPLE)
195207607Simp			printf("Requesting %s\n", name);
1961590Srgrimes
197207607Simp		n = send_rrq(peer, name, mode);
198207607Simp		if (n > 0) {
199207607Simp			printf("Cannot send RRQ packet\n");
200207607Simp			return;
201207607Simp		}
2021590Srgrimes
203207607Simp		/*
204207607Simp		 * The first packet we receive has the new destination port
205207607Simp		 * we have to send the next packets to.
206207607Simp		 */
207207607Simp		n = receive_packet(peer, recvbuffer,
208207607Simp		    MAXPKTSIZE, &from, timeoutpacket);
2091590Srgrimes
210207607Simp		/* We got something useful! */
211207607Simp		if (n >= 0) {
212207607Simp			((struct sockaddr_in *)&peer_sock)->sin_port =
213207607Simp			    ((struct sockaddr_in *)&from)->sin_port;
2141590Srgrimes			break;
215207607Simp		}
2161590Srgrimes
217207607Simp		/* We should retry if this happens */
218207607Simp		if (n == RP_TIMEOUT) {
219207607Simp			printf("Try %d, didn't receive answer from remote.\n",
220207607Simp			    i + 1);
221207607Simp			continue;
222207607Simp		}
2231590Srgrimes
224207607Simp		/* Otherwise it is a fatal error */
2251590Srgrimes		break;
226207607Simp	}
227209550Sgavin	if (i == 12) {
228209550Sgavin		printf("Transfer timed out.\n");
229209550Sgavin		return;
230209550Sgavin	}
231207607Simp	if (rp->th_opcode == ERROR) {
232207607Simp		tftp_log(LOG_ERR, "Error code %d: %s", rp->th_code, rp->th_msg);
233207607Simp		return;
234207607Simp	}
2351590Srgrimes
236207607Simp	if (write_init(fd, NULL, mode) < 0) {
237207607Simp		warn("write_init");
238207607Simp		return;
2391590Srgrimes	}
2401590Srgrimes
241207607Simp	/*
242207607Simp	 * If the first packet is an OACK packet instead of an DATA packet,
243207607Simp	 * handle it different.
244207607Simp	 */
245207607Simp	if (rp->th_opcode == OACK) {
246207607Simp		if (!options_rfc_enabled) {
247207607Simp			printf("Got OACK while options are not enabled!\n");
248207607Simp			send_error(peer, EBADOP);
249207607Simp			return;
250207607Simp		}
2511590Srgrimes
252207607Simp		parse_options(peer, rp->th_stuff, n + 2);
2531590Srgrimes
254207607Simp		n = send_ack(peer, 0);
255207607Simp		if (n > 0) {
256207607Simp			printf("Cannot send ACK on OACK.\n");
257207607Simp			return;
258207607Simp		}
259207607Simp		block = 0;
260207607Simp		tftp_receive(peer, &block, &tftp_stats, NULL, 0);
261207607Simp	} else {
262207607Simp		block = 1;
263207607Simp		tftp_receive(peer, &block, &tftp_stats, rp, n);
2641590Srgrimes	}
26594443Sume
266207607Simp	write_close();
267207607Simp	if (tftp_stats.amount > 0)
268207607Simp		printstats("Received", verbose, &tftp_stats);
269207607Simp	return;
27094443Sume}
271