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